PHP Toolkit 13.1 has a broken implementation of upsert() in SforceEnterpriseClient. The object type is hard coded as 'Contact', and there is no way to specify a different object type. Apply the following patch to fix:

--- phptoolkit-13_1/soapclient/SforceEnterpriseClient.php	2009-09-04 14:38:00.000000000 -0400
+++ phptoolkit-13_1/soapclient/SforceEnterpriseClient.php.new	2010-07-14 00:54:46.000000000 -0400
@@ -83,11 +83,11 @@ class SforceEnterpriseClient extends Sfo
    * @param array  $sObjects  Array of sObjects
    * @return UpsertResult
    */
-  public function upsert($ext_Id, $sObjects) {
+  public function upsert($ext_Id, $sObjects, $type) {
     $arg = new stdClass;
     $arg->externalIDFieldName = new SoapVar($ext_Id, XSD_STRING, 'string', 'http://www.w3.org/2001/XMLSchema');
     foreach ($sObjects as &$sObject) {
-      $sObject = new SoapVar($sObject, SOAP_ENC_OBJECT, 'Contact', $this->namespace);
+      $sObject = new SoapVar($sObject, SOAP_ENC_OBJECT, $type, $this->namespace);
     }
     $arg->sObjects = $sObjects;
     return parent::_upsert($arg);

As a previous wiki editor mentioned, it is not apparent where to submit a patch or report a bug. I decided to simply post a patch.

EDIT:

here's a patch I'd consider better since it doesn't break existing uses. Clearly Salesforce cares nothing about maintaining this PHP library given how sloppy the code is and since it's nearly untouched since 2007.

Index: soapclient/SforceEnterpriseClient.php
===================================================================
--- soapclient/SforceEnterpriseClient.php	(revision 188)
+++ soapclient/SforceEnterpriseClient.php	(working copy)
@@ -45,8 +45,7 @@
   /**
    * Adds one or more new individual objects to your organization's data.
    * @param array $sObjects    Array of one or more sObjects (up to 200) to create.
-   * @param AssignmentRuleHeader $assignment_header is optional.  Defaults to NULL
-   * @param MruHeader $mru_header is optional.  Defaults to NULL
+   * @param string $type  The type of objects being created.
    * @return SaveResult
    */
   public function create($sObjects, $type) {
@@ -61,6 +60,7 @@
   /**
    * Updates one or more new individual objects to your organization's data.
    * @param array sObjects    Array of sObjects
+   * @param string $type  The type of objects being updated.
    * @param AssignmentRuleHeader $assignment_header is optional.  Defaults to NULL
    * @param MruHeader $mru_header is optional.  Defaults to NULL
    * @return UpdateResult
@@ -81,13 +81,14 @@
    *
    * @param string $ext_Id        External Id
    * @param array  $sObjects  Array of sObjects
+   * @param string $type  The type of objects being upserted.
    * @return UpsertResult
    */
-  public function upsert($ext_Id, $sObjects) {
+  public function upsert($ext_Id, $sObjects, $type = 'Contact') {
     $arg = new stdClass;
     $arg->externalIDFieldName = new SoapVar($ext_Id, XSD_STRING, 'string', 'http://www.w3.org/2001/XMLSchema');
     foreach ($sObjects as &$sObject) {
-      $sObject = new SoapVar($sObject, SOAP_ENC_OBJECT, 'Contact', $this->namespace);
+      $sObject = new SoapVar($sObject, SOAP_ENC_OBJECT, $type, $this->namespace);
     }
     $arg->sObjects = $sObjects;
     return parent::_upsert($arg);
@@ -97,7 +98,7 @@
    * Merge records
    *
    * @param stdclass $mergeRequest
-   * @param String $type
+   * @param String $type  The type of objects being merged.
    * @return unknown
    */
   public function merge($mergeRequest, $type) {