Salesforce / PHP - الرسائل الصادرة (SOAP) - الذاكرة قضية الحد؟ DOMDocument :: loadXML () نهاية مبكرة من البيانات في قضية العلامة؟

StackOverflow https://stackoverflow.com/questions/2462804

سؤال

وUPDATE:

وOK I حظيت بها، يشبه fread وجود قيود حجم الملف، تغيير هذا إلى

وfile_get_contents('php://input')

و، ولكن الآن وبعد SF إعطاء java.net.SocketTimeoutException: قراءة مهلة خطأ وليس على الجانب PHP. كما أنني قد أضفت set_time_limit (0)؛ إلى البرنامج النصي PHP التي إذا فهمت تنفيذ البرنامج النصي لطالما أنه يأخذ بشكل صحيح. أي أفكار؟

وراجع للشغل: I يمكن معالجة ما يصل إلى 25 (أي لقد اختبرت) ولكن ليس 100


وأنا باستخدام Salesforce لإرسال الرسائل الصادرة (عبر SOAP) إلى ملقم آخر. يمكن معالجة خادم حوالي 8 رسائل في وقت واحد، ولكن لن يرسلون الملف ACK إذا كان الطلب SOAP يحتوي على أكثر من 8 رسائل. SF يمكن ارسال ما يصل الى 100 رسالة صادرة في طلب 1 SOAP وأعتقد أن هذا هو الذي يسبب مشكلة الذاكرة مع PHP. إذا كنت معالجة الرسائل الصادرة 1 من 1 أنهم جميعا الذهاب من خلال ما يرام، وأستطيع أن أفعل حتى 8 في وقت واحد مع أي قضايا. ولكن مجموعات أكبر لا تعمل.

خطأ في SF:

org.xml.sax.SAXParseException: Premature end of file

وتبحث في الخطأ HTTP بتسجيل أرى أن تبدو رسالة SOAP الواردة إلى أن يكون الحصول على قطع من الذي يلقي التحذير PHP قائلا:

DOMDocument::loadXML() ... Premature end of data in tag ...

وPHP خطأ فادح:

Call to a member function getAttribute() on a non-object

وهذا يقودني إلى الاعتقاد بأن PHP هو وجود مشكلة الذاكرة ولا يمكن تحليل الرسالة الواردة نظرا لانها الحجم.

وأنا أفكر أنا يمكن أن مجرد مجموعة:

ini_set('memory_limit', '64M'); // This has done nothing to fix the problem

ولكن هذا من شأنه أن يكون النهج الصحيح؟ هل هناك طريقة يمكنني أن تعيين هذا إلى زيادة مع طلب SOAP الواردة حيوي؟

وUPDATE: إضافة بعض التعليمات البرمجية

 /**
 * To parse out incoming SOAP requests and insert the values into a database table
 * 
 * {@link http://www.mikesimonds.com/salesforce-php-tutorials/95-using-salesforce-outbound-soap-messages-php-2.html}
 */

// Might need more memory?
ini_set('memory_limit', '64M'); // So far this does nothing to help the bulk requests

/**
 * Set the document root path
 * @var $doc_root
 */
$doc_root = $_SERVER['DOCUMENT_ROOT'];


/**
 * This is needed for the $sObject object variable creation
 * found in phptoolkit-11_0 package available from SalesForce
 */
require_once(DOC_ROOT . SALESFORCE_DIRECTORY . SALESFORCE_PHP_TOOLKIT .'/soapclient/SforcePartnerClient.php'); 

/**
 * Reads SOAP incoming message from Salesforce/MAPS
 * @var incoming SOAP request
 */
$data = fopen('php://input','rb');

$headers = getallheaders();
$content_length = $headers['Content-Length'];
$buffer_length = 1000; // Do I need this buffer? 
$fread_length = $content_length + $buffer_length;

$content = fread($data,$fread_length);

/**
 * Parse values from soap string into DOM XML
 */
$dom = new DOMDocument();
$dom->loadXML($content);
$resultArray = parseNotification($dom);
$sObject = $resultArray["sObject"];

// Can remove this once I figure out the bug
$testing = false;

// Set $testing to true if you would like to see the incoming SOAP request from SF
if($testing) {
    // Make it look nice
    $dom->formatOutput = true;

    // Write message and values to a file
    $fh = fopen(LOG_FILE_PATH.'/'.LOG_FILE_NAME,'a');
    fwrite($fh,$dom->saveXML());
    $ret_val = fclose($fh);
}

/**
 * Checks if the SOAP request was parsed out,
 * the $sObject->ACK is set to a string value of true in
 * the parseNotification()
 * @var $sObject->ACK
 */
if($sObject->ACK == 'true') {
    respond('true');
} else {
    // This means something might be wrong
    mail(BAD_ACK_TO_EMAIL,BAD_ACK_EMAIL_SUBJECT,$content,BAD_ACK_EMAIL_HEADER_WITH_CC);
    respond('false');
}

if(WRITE_OUTPUT_TO_LOG_FILE) {
    // Clear variable
    $fields_string = "";

    /**
     * List common values of the SOAP request
     * @var $sObject
     */
    $fields_string .= "Organization Id: " . $sObject->OrganizationId . "\n";
    $fields_string .= "Action Id: " . $sObject->ActionId . "\n";
    //$fields_string .= "Session Id: " . $sObject->SessionId . "\n"; // Session Id is not being passed right now, don't need it
    $fields_string .= "Enterprise URL: " . $sObject->EnterpriseUrl . "\n";
    $fields_string .= "Partner URL: " . $sObject->PartnerUrl . "\n"; 

    /**
     * @todo: Still need to add the notification Id to an array or some sort
     */
    //$fields_string .= "Notification Id: " . $sObject->NotificationId . "\n"; 
    //$fields_string .= '<pre>' . print_r($sObject->NotificationId,true) . '</pre>';

    /**
     * now you have an array as $record and you can use the
     * data as you need to for updates or calls back to salesforce
     * whatever you need to do is here
     * @var $resultArray['MapsRecords']
     */
    foreach ($resultArray['MapsRecords'] as $record) {
        // Just prints the fields in the array
        $fields_string .= '<pre>' . print_r($record,true) . '</pre>';  
    }

    // Flag used to send ACK response
    $fields_string .= "\nACK Flag: " . $sObject->ACK;

    // $content_length
    $fields_string .= "\nContent Length (Outbound Message Size): " . $content_length;

    // Close Border to separate each request
    $fields_string .= "\n /*********************************************/ \n";

    // Write message and values to a file
    $fh = fopen(LOG_FILE_PATH.'/'.LOG_FILE_NAME,'a');
    fwrite($fh,$fields_string);
    $ret_val = fclose($fh); 
}

/**
 * Parse a Salesforce.com Outbound Message notification SOAP packet
 * into an array of notification parms and an sObject. 
 * @param   XML [$domDoc] SOAP request as XML
 * @return  object/array[ $result] typecast XML to object of arrays
 **/
function parseNotification($domDoc) {  
    // Parse Notification parameters into result array
    $result = array("OrganizationId" => "",
                    "ActionId" => "",
                    "SessionId" => "",
                    "EnterpriseUrl" => "",
                    "PartnerUrl" => "",
                    "sObject" => null,
                    "MapsRecords" => array());

    // Create sObject and fill fields provided in notification
    $sObjectNode = $domDoc->getElementsByTagName("sObject")->item(0);
    $sObjType = $sObjectNode->getAttribute("type");

    if(substr_count($sObjType,"sf:")) {
        $sObjType = substr($sObjType,3);
    }

    $result["sObject"] = new SObject($sObjType);
    $result["sObject"]->type = $sObjType;    
    $result["sObject"]->OrganizationId = $domDoc->getElementsByTagName("OrganizationId")->item(0)->textContent;
    $result["sObject"]->ActionId = $domDoc->getElementsByTagName("ActionId")->item(0)->textContent;
    $result["sObject"]->SessionId = $domDoc->getElementsByTagName("SessionId")->item(0)->textContent;
    $result["sObject"]->EnterpriseUrl = $domDoc->getElementsByTagName("EnterpriseUrl")->item(0)->textContent;
    $result["sObject"]->PartnerUrl = $domDoc->getElementsByTagName("PartnerUrl")->item(0)->textContent;

    /**
     * @todo: for multiple requests, need to add an array of Notification Id's
     *        might move this inside the loop or something
     *        might not need to do this as well
     */
    //$notificationId[] = $domDoc->getElementsByTagName("Id")->item(0)->textContent;
    //$result["sObject"]->NotificationId = $notificationId;

    $sObjectNodes = $domDoc->getElementsByTagNameNS('urn:sobject.BLAH.com','*');
    $result["sObject"]->fieldnames = array();
    $count = 0;
    $tempMapRecord = array();

    // Loop through each notification sObject
    foreach ($sObjectNodes as $node) {
        if ($node->localName == "Id") {
            if ($count > 0) {
                $result["MapsRecords"][] = $tempMapRecord;
                $tempMapRecord = array();                          
            }
            // @note: added the strip_tags() to strip out all HTML tags
            $tempMapRecord[$node->localName] = strip_tags($node->textContent);
        } else {
            // @note: added the strip_tags() to strip out all HTML tags
            $tempMapRecord[$node->localName] = strip_tags($node->textContent);
        }        
        $count++;

        // set flag for ACK
        $result["sObject"]->ACK = 'true';
    }
    // Finish last item
    $result["MapsRecords"][] = $tempMapRecord;

    return $result;
}

/**
 * ACK to SalesForce, True/False (Prints header)
 * @param object $tf
 * @return $ACK
 */
function respond($tf) {
    $ACK = <<<ACK
<?xml version = "1.0" encoding = "utf-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <soapenv:Body>
        <notifications xmlns="http://BLAH.com/outbound">
            <Ack>$tf</Ack>
        </notifications>
    </soapenv:Body>
</soapenv:Envelope>
ACK;

    print trim($ACK); 
}

مثال SOAP طلب من'سايلزفورس 'سيكون هناك العديد من العقد إخطار إضافة إلى طلب أكبر.

<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
 <soapenv:Body>
 <notifications xmlns="http://BLAH.com/outbound">
  <OrganizationId>BLAH</OrganizationId>
  <ActionId>BLAH</ActionId>
  <SessionId xsi:nil="true"/>
  <EnterpriseUrl>https://BLAH.com/</EnterpriseUrl>
  <PartnerUrl>https://BLAH.com/</PartnerUrl>
  <Notification>
   <Id>BLAH</Id>
   <sObject xmlns:sf="urn:sobject.BLAH.com" xsi:type="sf:Case">
    <sf:Id>BLAH</sf:Id>
    <sf:CaseNumber>BLAH</sf:CaseNumber>
    <sf:Case_Owner_ID_hidden__c>BLAH</sf:Case_Owner_ID_hidden__c>
    <sf:CreatedDate>2010-03-17T12:11:33.000Z</sf:CreatedDate>
    <sf:LastModifiedDate>2010-03-17T15:21:29.000Z</sf:LastModifiedDate>
    <sf:OwnerId>BLAH</sf:OwnerId>
    <sf:Status>BLAH</sf:Status>
   </sObject>
  </Notification>
 </notifications>
 </soapenv:Body>
</soapenv:Envelope>
هل كانت مفيدة؟

المحلول

وسوف قضية الذاكرة وPHP يقول

PHP Fatal error: Out of memory (allocated 250871808)...

وهذا هو الأرجح سيتم إنهاؤها أو اقتطاع تنشأ البيانات من منصة Salesforce بشكل غير صحيح - محاولة تصحيح الخطأ الأول من SF

وتحرير:

وOK، يبدو وكأنك الاستيلاء على البيانات بطريقة العتيقة. حاول استبدال fread() مع stream_get_contents()، وأيضا echo $content مباشرة بعد الحصول عليها للتحقق من الانتاج.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top