2011-09-22 11 views
6

किसी कारण से, zlib.deflate फ़िल्टर stream_socket_pair() द्वारा उत्पन्न सॉकेट जोड़े के साथ काम नहीं कर रहा प्रतीत होता है। जो कि दूसरी सॉकेट से पढ़ा जा सकता है वह दो-बाइट ज़्लिब हेडर है, और उसके बाद सबकुछ शून्य है।सॉकेट जोड़ी के साथ zlib फ़िल्टर का उपयोग

उदाहरण:

<?php 
list($in, $out) = stream_socket_pair(STREAM_PF_UNIX, 
            STREAM_SOCK_STREAM, 
            STREAM_IPPROTO_IP); 

$params = array('level' => 6, 'window' => 15, 'memory' => 9); 

stream_filter_append($in, 'zlib.deflate', STREAM_FILTER_WRITE, $params); 
stream_set_blocking($in, 0); 
stream_set_blocking($out, 0); 

fwrite($in, 'Some big long string.'); 
$compressed = fread($out, 1024); 
var_dump($compressed); 

fwrite($in, 'Some big long string, take two.'); 
$compressed = fread($out, 1024); 
var_dump($compressed); 

fwrite($in, 'Some big long string - third time is the charm?'); 
$compressed = fread($out, 1024); 
var_dump($compressed); 

आउटपुट:

string(2) "x�" 
string(0) "" 
string(0) "" 

अगर मैं stream_filter_append() करने के लिए कॉल बाहर टिप्पणी, धारा लेखन/कार्य पढ़ने सही ढंग से, डेटा के साथ अपनी संपूर्णता में फेंक दिया जा रहा है सभी तीन बार , और यदि मैं सॉकेट जोड़ी के बजाय ज़्लिब फ़िल्टर की गई स्ट्रीम को फ़ाइल में निर्देशित करता हूं, तो संकुचित डेटा सही ढंग से लिखा जाता है। तो दोनों भागों सही ढंग से अलग से काम करते हैं, लेकिन एक साथ नहीं। क्या यह एक PHP बग है जिसे मुझे रिपोर्ट करना चाहिए, या मेरे हिस्से में एक त्रुटि है?

यह प्रश्न this related question के समाधान से ब्रांच किया गया है।

उत्तर

2

the C source code के माध्यम से देख रहे हैं, समस्या यह है कि फिल्टर हमेशा zlib's deflate() function को संकुचित आउटपुट के उत्पादन से पहले कितना डेटा जमा करने देता है। डिफ्लेट फ़िल्टर तब तक एक नई डेटा बाल्टी नहीं बनाता है जब तक कि deflate() कुछ डेटा आउटपुट (लाइन 235 देखें) या PSFS_FLAG_FLUSH_CLOSE फ्लैग बिट सेट (लाइन 250) है। यही कारण है कि जब तक आप $in बंद नहीं करते हैं तब तक आप केवल हेडर बाइट्स देखते हैं; deflate() पर पहला कॉल दो शीर्ष बाइट्स आउटपुट करता है, इसलिए data->strm.avail_out 2 है और इन दो बाइट्स को पास करने के लिए एक नई बाल्टी बनाई गई है।

ध्यान दें कि fflush() zlib फ़िल्टर के साथ ज्ञात समस्या के कारण काम नहीं करता है। देखें: Bug #48725 Support for flushing in zlib stream

दुर्भाग्यवश, इस पर एक अच्छा काम नहीं दिख रहा है। मैंने php_user_filter को बढ़ाकर PHP में एक फ़िल्टर लिखना शुरू किया, लेकिन php_user_filter फ्लैग बिट्स का पर्दाफाश नहीं करता है, केवल flags & PSFS_FLAG_FLUSH_CLOSE (filter() विधि का चौथा पैरामीटर, एक बूलियन तर्क आमतौर पर $closing नामित)। बग # 48725 को ठीक करने के लिए आपको सी स्रोतों को स्वयं संशोधित करने की आवश्यकता होगी। वैकल्पिक रूप से, इसे फिर से लिखें।

व्यक्तिगत तौर पर मैं विचार करेंगे यह फिर से लिख क्योंकि वहाँ कोड के साथ कुछ भौंह जुटाने मुद्दों हो रहा है: क्योंकि जब लेखन, मैं क्यों flags कुछ भी हो सकता है पता नहीं है

  • status = deflate(&(data->strm), flags & PSFS_FLAG_FLUSH_CLOSE ? Z_FULL_FLUSH : (flags & PSFS_FLAG_FLUSH_INC ? Z_SYNC_FLUSH : Z_NO_FLUSH)); अजीब लगता है PSFS_FLAG_NORMAL के अलावा। क्या & एक ही समय में फ्लश करना संभव है?किसी भी मामले में, झंडे को संभालने के लिए while लूप के बाहर "इन" बाल्टी ब्रिगेड के माध्यम से किया जाना चाहिए, जैसे PSFS_FLAG_FLUSH_CLOSE इस लूप के बाहर कैसे संभाला जाता है।
  • लाइन 221, memcpy से data->strm.next_in इस तथ्य को अनदेखा करता है कि data->strm.avail_in गैर-शून्य हो सकता है, इसलिए संपीड़ित आउटपुट लिखने के कुछ डेटा को छोड़ सकता है। देखें, उदाहरण के लिए, zlib पुस्तिका से निम्न पाठ:

    नहीं सभी इनपुट संसाधित किया जा सकता है (क्योंकि उत्पादन बफर में पर्याप्त जगह नहीं है वहाँ), next_in और avail_in अपडेट किया जाता है और प्रसंस्करण इस पर फिर से शुरू होगा deflate() की अगली कॉल के लिए इंगित करें।

    दूसरे शब्दों में, यह संभव है कि avail_in गैर-शून्य है।

  • if लाइन 235, if (data->strm.avail_out < data->outbuf_len) पर कथन शायद if (data->strm.avail_out) या शायद if (data->strm.avail_out > 2) होना चाहिए।
  • मुझे यकीन नहीं है कि क्यों *bytes_consumed = consumed;*bytes_consumed += consumed; नहीं है। http://www.php.net/manual/en/function.stream-filter-register.php पर उदाहरण स्ट्रीम अपडेट करने के लिए += का उपयोग करें।

संपादित करें:*bytes_consumed = consumed; सही है। The standard filter implementations सभी का उपयोग += के बजाय size_t मान को पांचवें पैरामीटर द्वारा इंगित करने के लिए उपयोग करें। इसके अलावा, पीएचपी पक्ष पर $consumed += ... प्रभावी रूप से पर += पर अनुवाद करता है (ext/standard/user_filters.c की लाइन 206 और 231 देखें), देशी फिल्टर फ़ंक्शन को NULL पॉइंटर या size_t पर पॉइंटर पांचवें तर्क के लिए 0 पर सेट किया गया है (main/streams/filter.c की लाइन 361 और 452 देखें)।

+0

स्पष्टीकरण के लिए बहुत बहुत धन्यवाद। मैंने रूबी में एक ही प्रोजेक्ट को कार्यान्वित किया और इसे 'Zlib :: SYNC_FLUSH' को' Zlib :: deflate() 'के दूसरे तर्क के रूप में कार्य करने के लिए पास करने के लिए समाप्त हो गया। मुझे लगता है कि यह लिख रहा है और फिर लिखने के तुरंत बाद flushing। मुझे लगता है कि PHP केवल 'Z_SYNC_FLUSH' का उपयोग कर रहा है यदि 'PSFS_FLAG_FLUSH_INC' ध्वज सेट किया गया है, लेकिन जैसा कि आपने कहा था, ध्वज बिट्स का खुलासा नहीं होता है। – FtDRbwLXw6

1

डेटा पढ़ने से पहले डेटा फ्लैश करने के बाद आपको स्ट्रीम को बंद करने की आवश्यकता है।

list($in, $out) = stream_socket_pair(STREAM_PF_UNIX, 
            STREAM_SOCK_STREAM, 
            STREAM_IPPROTO_IP); 

$params = array('level' => 6, 'window' => 15, 'memory' => 9); 

stream_filter_append($out, 'zlib.deflate', STREAM_FILTER_WRITE, $params); 
stream_set_blocking($out, 0); 
stream_set_blocking($in, 0); 

fwrite($out, 'Some big long string.'); 
fclose($out); 
$compressed = fread($in, 1024); 
echo "Compressed:" . bin2hex($compressed) . "<br>\n"; 


list($in, $out) = stream_socket_pair(STREAM_PF_UNIX, 
            STREAM_SOCK_STREAM, 
            STREAM_IPPROTO_IP); 

$params = array('level' => 6, 'window' => 15, 'memory' => 9); 

stream_filter_append($out, 'zlib.deflate', STREAM_FILTER_WRITE, $params); 
stream_set_blocking($out, 0); 
stream_set_blocking($in, 0); 


fwrite($out, 'Some big long string, take two.'); 
fclose($out); 
$compressed = fread($in, 1024); 
echo "Compressed:" . bin2hex($compressed) . "<br>\n"; 

list($in, $out) = stream_socket_pair(STREAM_PF_UNIX, 
            STREAM_SOCK_STREAM, 
            STREAM_IPPROTO_IP); 

$params = array('level' => 6, 'window' => 15, 'memory' => 9); 

stream_filter_append($out, 'zlib.deflate', STREAM_FILTER_WRITE, $params); 
stream_set_blocking($out, 0); 
stream_set_blocking($in, 0); 

fwrite($out, 'Some big long string - third time is the charm?'); 
fclose($out); 
$compressed = fread($in, 1024); 
echo "Compressed:" . bin2hex($compressed) . "<br>\n"; 

कि पैदा करता है: संपीडित: 789c0bcecf4d5548ca4c57c8c9cf4b57282e29cacc4bd70300532b079c संपीडित: 789c0bcecf4d5548ca4c57c8c9cf4b57282e29cacc4bd7512849cc4e552829cfd70300b1b50b07 संपीडित: 789c0bcecf4d5548ca4c57c8c9cf4b57282e29ca0452ba0a25199945290a259940c9cc62202f55213923b128d71e008e4c108c

इसके अलावा, मैं $ में मुझे उलझन में $ के लिए लिख क्योंकि बंद और $।

+0

उत्तर के लिए धन्यवाद, लेकिन यह समाधान एक व्यवहार्य नहीं है।प्रत्येक लेखन के बाद सॉकेट खोलने/बंद करने के लिए ओवरहेड स्वयं में और उसके लिए निषिद्ध होगा, लेकिन यह प्रत्येक लेखन के बाद ज़्लिब फ़िल्टर को भी नष्ट कर रहा है, जो कार्यान्वयन को तोड़ देगा। एक zlib फ़िल्टर का उपयोग करने का बिंदु इतना है कि लगातार लिखने वाले एक ही फ़िल्टर का उपयोग करते हैं। निश्चित रूप से बंद होने के बिना फ्लश करने का कोई तरीका होना चाहिए? मैंने बिना किसी किस्मत के पहले 'fflush()' पहले कोशिश की है। ** संपादित करें: ** अधिक स्पष्ट होने के लिए, प्रत्येक लेखन में हेडर भेजना कार्यान्वयन को तोड़ देगा, क्योंकि यह केवल एक बार भेजा जाना है। – FtDRbwLXw6

3

मैंने PHP स्रोत कोड पर काम किया था और एक फिक्स पाया।

को समझने के लिए क्या होता है मैं एक

.... 
for ($i = 0 ; $i < 3 ; $i++) { 
    fwrite($s[0], ...); 
    fread($s[1], ...); 
    fflush($s[0], ...); 
    fread($s[1], ...); 
    } 

पाश दौरान कोड का पता लगाया था और मैंने पाया कि deflate समारोह Z_SYNC_FLUSH ध्वज सेट के साथ कहा जाता है कभी नहीं है क्योंकि कोई नया डेटा backets_in ब्रिगेड में मौजूद हैं।

मेरे ठीक प्रबंधन करने के लिए है (PSFS_FLAG_FLUSH_INC झंडा AND सेट किया गया है कोई पुनरावृत्तियों Deflate समारोह मामले पर प्रदर्शन कर रहे हैं) का विस्तार

if (flags & PSFS_FLAG_FLUSH_CLOSE) { 

प्रबंध FLUSH_INC भी:

if (flags & PSFS_FLAG_FLUSH_CLOSE || (flags & PSFS_FLAG_FLUSH_INC && to_be_flushed)) { 

This downloadable patch के लिए है debian squeeze PHP का संस्करण लेकिन फ़ाइल का वर्तमान गिट संस्करण इसके करीब है इसलिए मुझे लगता है कि फिक्स पोर्ट बस है (कुछ लाइनें)।

यदि कुछ दुष्प्रभाव उत्पन्न होते हैं तो कृपया मुझसे संपर्क करें।

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