2012-11-01 40 views
6

से PHP में पोस्ट डेटा पढ़ना मैं कुछ बाहरी सेवा से अनुरोध करने के लिए PHP में cUrl का उपयोग कर रहा हूं।सीयूआरएल

काफी दिलचस्प है, सर्वर कच्चे "बहुखण्डीय/फार्म-डेटा" के बदले बाइनरी फ़ाइल डेटा के साथ दे रहा है।

मेरी वेबसाइट एक साझा होस्टिंग का उपयोग कर रही है, इसलिए पीईसीएल HTTP एक विकल्प नहीं है।

क्या PHP के साथ इस डेटा को पार्स करने का कोई तरीका है?

नमूना कोड:

$response = curl_exec($cUrl); 

/* $response is raw "multipart/form-data" string 

    --MIMEBoundaryurn_uuid_DDF2A2C71485B8C94C135176149950475371 
    Content-Type: application/xop+xml; charset=utf-8; type="text/xml" 
    Content-Transfer-Encoding: binary 

    (xml data goes here) 

    --MIMEBoundaryurn_uuid_DDF2A2C71485B8C94C135176149950475371 
    Content-Type: application/zip 
    Content-Transfer-Encoding: binary 

    (binary file data goes here) 

*/ 

संपादित करें: मैं एक स्थानीय होस्ट HTTP अनुरोध के जवाब पाइप कोशिश की, लेकिन जवाब डेटा पीएचपी प्रक्रिया में अनुमति स्मृति आकार से अधिक होने की संभावना है। एमएम सीमा का विस्तार करना बहुत व्यावहारिक नहीं है, यह क्रिया नाटकीय रूप से सर्वर प्रदर्शन को नाटकीय रूप से कम कर देती है।

यदि मूल प्रश्न के कोई विकल्प नहीं हैं, तो आप PHP में स्ट्रीम के संदर्भ में एक्सएमएल पार्सिंग के साथ बहुत बड़े POST अनुरोधों को संभालने का एक तरीका सुझा सकते हैं।

मुझे पता है कि यह कठिन होगा, कृपया टिप्पणी करें। मैं चर्चाओं के लिए खुला हूं।

+1

शायद आप एक एमआईएमई मेल पार्सिंग लाइब्रेरी का उपयोग कर सकते हैं। Http://stackoverflow.com/questions/1238642/how-to-extract-mail-atachment-with-php/1240048#1240048 – Barmar

+0

यह एक शुद्ध 'फॉर्म-डेटा' है और इसमें मेल हेडर नहीं हैं, लेकिन मैं कोशिश करो। वास्तव में कोशिश करने से पहले मैं इसे समाधान के बहुत करीब देखता हूं। – Vicary

+0

टिप्पणी के लिए रेट किया गया क्योंकि चंद्र नव वर्ष समाप्त होने से पहले बक्षीस खत्म हो जाएगा, इससे पहले कि मुझे कार्यालय में कोड प्राप्त करने का मौका मिले। – Vicary

उत्तर

4

यदि आपको प्रतिक्रिया से ज़िप फ़ाइल की आवश्यकता है तो मुझे लगता है कि आप कर्ल प्रतिक्रिया को बचाने के लिए केवल एक टीएमपी फ़ाइल लिख सकते हैं, और वर्कअराउंड के रूप में स्ट्रीम कर सकते हैं: मल्टीपार्ट कर्ल के साथ कभी कोशिश नहीं की, लेकिन मुझे लगता है कि इसे काम करना चाहिए ।

$fh = fopen('/tmp/foo', 'w'); 
$cUrl = curl_init('http://example.com/foo'); 
curl_setopt($cUrl, CURLOPT_FILE, $fh); // redirect output to filehandle 
curl_exec($cUrl); 
curl_close($cUrl); 
fclose($fh); // close filehandle or the file will be corrupted 

आप केवल एक प्रतिक्रिया

curl_setopt($cUrl, CURLOPT_HTTPHEADER, array('Accept: application/xml')); 
//That's a workaround since there is no available curl option to do so but http allows that 

के रूप में स्वीकार करने के लिए एक्सएमएल हेडर

curl_setopt($cUrl, CURLOPT_HEADER, FALSE); 

अक्षम करें और विकल्प जोड़ने के लिए चाहते हो सकता है आप कुछ भी लेकिन प्रतिक्रिया की एक्सएमएल भाग की जरूरत नहीं है [संपादित करें]

अंधेरे में एक शॉट ... आप इन के साथ परीक्षण कर सकते हैं curlopt सेटिंग्स के रूप में उल्लेख किया है मैं अपने curled पृष्ठों एक बहुखण्डीय प्रपत्र डेटा के साथ प्रतिक्रिया करने के लिए नहीं मिल सकता है इन मदद modifiying अगर कुछ भी

$headers = array (
    'Content-Type: multipart/form-data; boundary=' . $boundary, 
    'Content-Length: ' . strlen($requestBody), 
    'X-EBAY-API-COMPATIBILITY-LEVEL: ' . $compatLevel, // API version 
    'X-EBAY-API-DEV-NAME: ' . $devID, 
    'X-EBAY-API-APP-NAME: ' . $appID, 
    'X-EBAY-API-CERT-NAME: ' . $certID, 
    'X-EBAY-API-CALL-NAME: ' . $verb, 
    'X-EBAY-API-SITEID: ' . $siteID, 
    ); 

$cUrl = curl_init(); 
curl_setopt($cUrl, CURLOPT_URL, $serverUrl); 
curl_setopt($cUrl, CURLOPT_TIMEOUT, 30); 
curl_setopt($cUrl, CURLOPT_SSL_VERIFYPEER, 0); 
curl_setopt($cUrl, CURLOPT_SSL_VERIFYHOST, 0); 
curl_setopt($cUrl, CURLOPT_HTTPHEADER, $headers); 
curl_setopt($cUrl, CURLOPT_POST, 1); 
curl_setopt($cUrl, CURLOPT_POSTFIELDS, $requestBody); 
curl_setopt($cUrl, CURLOPT_RETURNTRANSFER, 1); 
curl_setopt($cUrl, CURLOPT_FAILONERROR, 0); 
curl_setopt($cUrl, CURLOPT_FOLLOWLOCATION, 1); 
curl_setopt($cUrl, CURLOPT_HEADER, 0); 
curl_setopt($cUrl, CURLOPT_USERAGENT, 'ebatns;xmlstyle;1.0'); 
curl_setopt($cUrl, CURLOPT_HTTP_VERSION, 1);  // HTTP version must be 1.0 
$response = curl_exec($cUrl); 

if (!$response) { 
    print "curl error " . curl_errno($cUrl) . PHP_EOL; 
} 
curl_close($cUrl); 

[संपादित द्वितीय]

यह सिर्फ एक कोशिश है देखने के लिए,।तो यहाँ मेरे साथ कोमल हो;)

$content_type = ""; //use last know content-type as a trigger 
$tmp_cnt_file = "tmp/tmpfile"; 
$xml_response = ""; // this will hold the "usable" curl response 
$hidx = 0; //header index.. counting the number of different headers received 

function read_header($cUrl, $string)// this will be called once for every line of each header received 
{ 
    global $content_type, $hidx; 
    $length = strlen($string); 
    if (preg_match('/Content-Type:(.*)/', $string, $match)) 
    { 
     $content_type = $match[1]; 
     $hidx++; 
    } 
    /* 
    should set $content_type to 'application/xop+xml; charset=utf-8; type="text/xml"' for the first 
    and to 'application/zip' for the second response body 

    echo "Header: $string<br />\n"; 
    */ 
    return $length; 
} 

function read_body($cUrl, $string) 
{ 
    global $content_header, $xml_response, $tmp_cnt_file, $hidx; 
    $length = strlen($string); 
    if(stripos ($content_type , "xml") !== false) 
     $xml_response .= $string; 
    elseif(stripos ($content_type, "zip") !== false) 
    { 
     $handle = fopen($tmp_cnt_file."-".$hidx.".zip", "a"); 
     fwrite($handle, $string); 
     fclose($handle); 
    } 
    /* 
    elseif {...} else{...} 
    depending on your needs 

    echo "Received $length bytes<br />\n"; 
    */ 
    return $length; 
} 

और निश्चित रूप से उचित curlopts

// Set callback function for header 
curl_setopt($cUrl, CURLOPT_HEADERFUNCTION, 'read_header'); 
// Set callback function for body 
curl_setopt($cUrl, CURLOPT_WRITEFUNCTION, 'read_body'); 

मत भूलना नहीं स्मृति समस्याओं के कारण एक चर को कर्ल प्रतिक्रिया को बचाने के लिए, सेट उम्मीद है कि आपको बस किसी भी तरह से $ xml_response में होना चाहिए।

//$response = curl_exec($cUrl); 
curl_exec($cUrl); 

और आप आप इस परिदृश्य में tmp/tmpfile-2 के साथ शुरू बनाया अस्थायी फ़ाइलों $xml_response का उल्लेख कर सकते हैं और अपने कोड पार्स करने के लिए। दोबारा, मैं किसी भी तरह से ऊपर दिए गए कोड का परीक्षण करने में सक्षम नहीं हूं। तो यह काम हो सकता है नहीं (लेकिन यह imho चाहिए;))

[संपादित करें तृतीय]

कहते हैं कि हम आने वाले सभी डेटा एक और (जावक) धारा के लिए सीधे लिखने के लिए कर्ल चाहते हैं, इस मामले में एक गर्तिका कनेक्शन

मैं अगर यह इस तरह ही आसान है यकीन नहीं है:

$fs = fsockopen($host, $port, $errno, $errstr); 
$cUrl = curl_init('http://example.com/foo'); 
curl_setopt($cUrl, CURLOPT_FILE, $fs); // redirect output to sockethandle 
curl_exec($cUrl); 
curl_close($cUrl); 
fclose($fs); // close handle 
बाकी

हमें बस थोड़ी चाल के साथ हमारे जाना जाता लिखने और हैडर कार्यों का उपयोग करना होगा

//first open the socket (before initiating curl) 
$fs = fsockopen($host, $port, $errno, $errstr); 
// now for the new callback function 
function socket_pipe($cUrl, $string) 
{ 
    global $fs; 
    $length = strlen($string); 
    fputs($fs, $string); // add NOTHING to the received line just send it to $fs; that was easy wasn't it? 
    return $length; 
} 
// and of course for the CURLOPT part 
// Set callback function for header 
curl_setopt($cUrl, CURLOPT_HEADERFUNCTION, 'socket_pipe'); 
// Set the same callback function for body 
curl_setopt($cUrl, CURLOPT_WRITEFUNCTION, 'socket_pipe'); 

// do not forget to 
fclose($fs); //when we're done 

बात यह है कि परिणाम संपादित नहीं किया जा रहा है और इसे $fs पर पाइप करने से यह आवश्यक हो जाएगा कि अपाचे एक निश्चित बंदरगाह पर सुन रहा है जिसे आप अपनी स्क्रिप्ट को असाइन करते हैं। या आप के बाद fsockopen

fputs($fp, "POST $path HTTP/1.0\n"); //where path is your script of course 
+0

मुझे पहले कर्ल अनुरोध से जो मिला वह 'मल्टीपार्ट/फॉर्म-डेटा' के प्रारूप में है जिसका उपयोग शायद ही कभी प्रतिक्रिया में किया जाता है, इसे फ़ाइल के रूप में भेजने के बाद अगले अनुरोध में PHP डेटा को '$ _FILES' के अंदर सीधे रखा जाएगा और PHP पेलोड को पार्स करने में कुछ भी नहीं करेगा। – Vicary

+0

इसलिए '$ _FILES' और' $ _POST' उसी फ़ाइल में संग्रहीत है, ओके। लेकिन फिर भी इसे php मेमोरी सीमा से अधिक होने से रोकना चाहिए जब आप फ़ाइल को हैंडलर से फिर से खोलते समय फ़ाइल को खोलते समय कर्ल प्रतिक्रिया के बजाय फ़ाइल को पार्स करते हैं। आप प्रतिक्रिया से हेडर और बॉडी आकार को पढ़ना चाहेंगे और इसे एक चर में स्टोर कर सकते हैं ताकि आप आसानी से प्रतिक्रिया-फ़ाइल के सही ऑफसेट पर जा सकें। अगर मुझे आज का समय मिल जाए तो मैं एक पूरा उदाहरण पोस्ट करूंगा। – itsid

+0

ठीक है .. यह अजीब बात है, मैंने एक कर्ल अनुरोध से 'मल्टीपार्ट/फॉर्म-डेटा' वापस पाने के लिए कड़ी मेहनत की लेकिन मैं नहीं कर सकता। यहां तक ​​कि अगर मैं upload.php के बजाय अपलोड-form.html को कर्ल नहीं करता हूं, तो फॉर्म क्रियाएं इंगित करती हैं। मुझे खेद है कि क्या आप इसे प्राप्त करने के लिए मुझे अपने 'CURLOPT_URL' यूआरएल को जानना चाहते हैं? – itsid

0

मैं माफी चाहता मैं ज्यादा मदद नहीं कर सकता है क्योंकि आप बहुत कोड डाल नहीं किया हूँ, लेकिन मैं याद मैं ने वही समस्या जब मैं curl_setopt विकल्पों के साथ खेल रहा था हो रही थी।

क्या आपने CURLOPT_BINARYTRANSFER का उपयोग किया था?

PHP दस्तावेज़ीकरण से ->CURLOPT_BINARYTRANSFER -> CURLOPT_RETURNTRANSFER का उपयोग होने पर कच्चे आउटपुट को वापस करने के लिए सही है।

+0

मामला यह है कि मुझे कच्चे मल्टीपार्ट/फॉर्म-डेटा प्रारूप में प्रतिक्रिया मिली, जो आमतौर पर केवल अनुरोधों के लिए उपयोग की जाती थी। मैं नहीं चाहता कि यह कच्चा हो, लेकिन कुछ प्रकार की पार्सिंग तंत्र अपाचे और PHP इसके बजाय मेरे कोड में आने से पहले करता है। – Vicary

0

सिर्फ CURLOPT_RETURNTRANSFER CURLOPT_POST

 $c = curl_init($url); 
     curl_setopt($c, CURLOPT_RETURNTRANSFER, true); 
     curl_setopt($c, CURLOPT_CONNECTTIMEOUT, 1); 
     curl_setopt($c, CURLOPT_TIMEOUT, 1); 
     curl_setopt($c, CURLOPT_POST, 1); 
     curl_setopt($c, CURLOPT_POSTFIELDS, 
        array()); 
     $rst_str = curl_exec($c); 
     curl_close($c); 
0

आप बाइनरी डेटा कुछ इस तरह कर रही है फिर से इकट्ठा कर सकते हैं सेट एक शीर्ष लेख पंक्ति सीधे जोड़ने की आवश्यकता होगी, मुझे आशा है कि यह मदद करता है।

$file_array = explode("\n\r", $file, 2); 
$header_array = explode("\n", $file_array[0]); 
foreach($header_array as $header_value) { 
    $header_pieces = explode(':', $header_value); 
    if(count($header_pieces) == 2) { 
    $headers[$header_pieces[0]] = trim($header_pieces[1]); 
    } 
} 
header('Content-type: ' . $headers['Content-Type']); 
header('Content-Disposition: ' . $headers['Content-Disposition']); 
echo substr($file_array[1], 1); 
0

यदि आपको बाइनरी डेटा की आवश्यकता नहीं है, तो क्या आपने नीचे कोशिश की है?

curl_setopt($c, CURLOPT_NOBODY, true); 

 संबंधित मुद्दे

  • कोई संबंधित समस्या नहीं^_^