PHP का उपयोग करके टार और gz अभिलेखागार के साथ काम करना

जैसा कि अक्सर ऐसा होता है, यह सब इस तथ्य के साथ शुरू हुआ कि मुझे कुछ ऐसा चाहिए था जो मुझे php का उपयोग करके tar.gz अभिलेखागार को संसाधित करने की अनुमति देता है। इंटरनेट पर चारों ओर घूमते हुए, मुझे यह जानकर आश्चर्य हुआ कि इस विषय पर कुछ भी स्वीकार्य नहीं था।

हमारे पास क्या है?

1. PHP के लिए PEAR एक्सटेंशन http://pear.php.net/package/Archive_Tar ठीक है, लेकिन मेरे मामले में अस्वीकार्य है, क्योंकि मेरे पास सर्वर सेटिंग्स तक पहुंच नहीं है। जबरन झाड़ू लगाना।
2. अलेक्सई वलेव का एक उत्कृष्ट लेख "php में tar.gz अभिलेखागार के साथ काम करना" । क्या जरूरत है, लेकिन अफसोस। मुझे "पारदर्शी" लाइसेंस प्राप्त एक समाधान की आवश्यकता थी, सवाल उठाने में सक्षम नहीं। इसलिए, बिट्रिक्स से पुस्तकालय का उपयोग भी अच्छा नहीं था।

वास्तव में, यह सब है

खोज इंजन को आगे बढ़ाने से कुछ भी उचित नहीं निकला। थोड़ा सोचने के बाद, मैंने लोकप्रिय net2ftp के कोड में क्रॉल किया, जो कि मुझे याद है, टार अभिलेखागार को पूरी तरह से संभालता है। यह पता चला कि विंसेंट ब्लेवेट , 2001 से एक pcltar.lib.php लाइब्रेरी है । GNU लाइसेंस सब कुछ जैसा है वैसा ही होना चाहिए। लेकिन! शुरुआत के लिए, मैं पुस्तकालय के आकार से ही भ्रमित हो गया था 127 किलोबाइट। खैर, मेरे पास पुराने दिनों से एक bikik है - मैं अभी भी बाइट्स गिनता हूं। फिर, मैं एक वर्ग के रूप में परिणाम चाहता था, न कि अलग-अलग कार्यों के रूप में। इसके अलावा, उत्साह में उछाल आया। मैं इसका पूरा पता लगाना चाहता था।

नतीजतन, मुझे टार आर्काइव संरचना (जो परवाह करता है, सूचना ब्लॉक का शीर्षक ब्लॉक यहां अच्छी तरह से चित्रित किया गया है ) का विवरण ढूंढना होगा और कोड का अध्ययन करना होगा। मैं नीचे परिणाम देता हूं। मैं समझता हूं कि कार्य विशिष्ट है, लेकिन शायद कोई काम आएगा।

तो, जैसा कि आप जानते हैं, आधुनिक अर्थों में टार अभिलेखागार नहीं है। टेप मीडिया पर डेटा को सहेजने के लिए डिज़ाइन किया गया, यह नहीं जानता कि कैसे संपीड़ित करना है, लेकिन बस कई फ़ाइलों को एक में जोड़ता है, अपने स्वयं के हेडर को जोड़ने और परिणामस्वरूप कोड को 512-बाइट ब्लॉकों की एक समान संख्या में जोड़ता है। फिर परिणाम पहले से ही संग्रहकर्ता द्वारा संपीड़ित किया जा सकता है। कौन सा? हां, कम से कम रार। कोई फर्क नहीं। हालांकि, परंपरागत रूप से, इसके लिए gzip और bzip2 प्रारूप का उपयोग किया जाता है। चूंकि वे सिर्फ दो फ़ाइलों को लिंक नहीं कर सकते (यह "एक कार्यक्रम - एक क्रिया" नीति यूनिक्स सिस्टम में अपनाई गई है)। PHP में gzip और bzip2 के लिए समर्थन तृतीय-पक्ष पुस्तकालयों द्वारा प्रदान किया जाता है, और हमारे लिए महत्वपूर्ण नहीं है। टार ही महत्वपूर्ण है।

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

100 बाइट्स नाम - नाम (एक रिश्तेदार पथ हो सकता है);
8 बाइट्स मोड फ़ाइल मोड
8 बाइट्स uid - उपयोगकर्ता आईडी
8 बाइट्स जीआईडी ​​- समूह आईडी
12 बाइट्स आकार - फ़ाइल का आकार, बाइट्स (ऑक्टल में एन्कोडेड)
12 बाइट्स माइम - UNIX युग के सेकंड में अंतिम संशोधन की तिथि और समय (ऑक्टेल में इनकोडेड)
8 बाइट्स चक्सम - हेडर का चेकसम (फाइल नहीं!)
1 बाइट टाइपफ्लैग - हमारे साथ फ़ाइल को परिभाषित करता है, या निर्देशिका: फ़ाइल - 0, निर्देशिका - 5
100 बाइट्स लिंकनाम - फाइल का लिंक
- आगे - "नए" प्रारूप के क्षेत्र - जादू के 6 बाइट्स - शब्द में "ustar", अर्थात। एक "नए" प्रारूप का संकेत
2 बाइट्स संस्करण - नए प्रारूप का संस्करण (अनुपस्थित हो सकता है)
32 बाइट्स नाम - स्वामी का नाम
32 बाइट्स gname - मालिक समूह का नाम
8 बाइट्स देवमेजर - डिवाइस कोड का उच्च बाइट
8 बाइट्स डेमिनोर - डिवाइस कोड का कम बाइट
155 बाइट्स उपसर्ग - नाम उपसर्ग (विस्तार)

अप्रयुक्त बाइट्स खाली होना चाहिए, हालांकि कोड "20" (स्थान) की अनुमति है।

इस डेटा के अधिकांश आम तौर पर आवश्यक नहीं है। व्यक्तिगत रूप से, मुझे नाम, आकार और तारीख में दिलचस्पी थी।

इसके बाद सूचना भाग खुद आता है, पूरक (ध्यान!) 512 बाइट्स के कई तक खाली बाइट्स के साथ। और अगली फाइल के लिए फिर से। जैसा कि आप देख सकते हैं, सब कुछ सरल है।

वास्तव में, यह ज्ञान फ़ाइल को पैक करने का प्रयास करने के लिए पर्याप्त है।

1. fopen कमांड (file_name) के साथ आर्काइव खोलें।

2. उपाधि। यह समस्या का सबसे कठिन हिस्सा है। मैंने उल्लेखित पुस्तकालय pcltar.lib.php से फ़ंक्शन का उपयोग करके, एक साइकिल का आविष्कार नहीं किया, इसे थोड़ा अनुकूलित किया। मैं बल्क के कारण यहां सभी कोड नहीं दूंगा, लेकिन सार निम्नलिखित क्रियाएं हैं:
- हम फ़ाइल का नाम, उसका आकार, निर्माण की तिथि, इसके लिए निर्धारित अधिकार निर्धारित करते हैं। निर्देशिकाओं के लिए, शून्य का आकार निर्दिष्ट करें;
- अप्रयुक्त पैरामीटर रिक्त घोषित किए जाते हैं;
- हम संख्यात्मक मापदंडों (आकार, तिथि) को ऑक्टल सिस्टम में परिवर्तित करते हैं;
- हम प्रत्येक पैरामीटर को संबंधित क्षेत्रों के घोषित आकार के अनुसार प्रारूपित करते हैं। यहां एक चाल है कि मैं तुरंत समझ में नहीं आया - वास्तव में, प्रत्येक क्षेत्र का एक महत्वपूर्ण हिस्सा क्षेत्र के आकार से एक बाइट कम होना चाहिए। अंतिम बाइट खाली होना चाहिए। अन्यथा, संग्रह को पढ़ा नहीं जा सकता।
- हम सभी मापदंडों को दो अलग-अलग लाइनों में पैक करते हैं। दो, क्योंकि उनके बीच एक हेडर चेकसम होना चाहिए।
- हम इस चेकसम पर विचार करते हैं, इसे उसी नियमों के अनुसार प्रारूपित करते हैं, और इसे पैक करते हैं।
- और अब हम आर्काइव में तीन पंक्तियों को क्रमिक रूप से लिखते हैं: मापदंडों का पहला भाग, चेकसम और दूसरा भाग।

हो गया! यहाँ निर्माण समय के लिए एक उदाहरण है:

$mtime = sprintf("%11s ", DecOct(filemtime($filename)));

pack("a100a8a8a8a12a12", …, …, …, …, …, $mtime);


3. फ़ाइल बॉडी के साथ सब कुछ सरल है, इसकी लाइब्रेरी में विंसेंट ब्लेवेट इसे पैक फ़ंक्शन के साथ भी संसाधित करता है। लेकिन मैंने कई फाइलों के साथ कई प्रयोग किए और पैकिंग / अनपैक करते समय कोई विकृतियाँ नहीं देखीं। इसलिए, उत्पादकता हासिल करने के लिए, मैंने ऐसा नहीं किया - इसका कोई मतलब नहीं है। हम सिर्फ फ़ाइल से डेटा पढ़ते हैं, निश्चित रूप से - इसे पहले खोलने के बाद, और संग्रह पर लिखें। चूंकि मेरे मामले में फ़ाइल का आकार काफी बड़ा हो सकता है, इसलिए मैं ब्लॉकों में ऐसा करता हूं। ब्लॉक आकार मैंने 50 Kb के लिए लिया।

$infile = fopen($filename, rb);
$j = ceil(filesize($filename) / 51200) + 1;
for($i=0; $i<$j; $i++){
$fr = fread($infile, 51200);
if ($this->tarmode == "tar")
@fputs($this->tarfile, $fr);
else
@gzputs($this->tarfile, $fr);
}
fclose($infile);


4. और अब हम "सम" तक आते हैं। ऐसा करने के लिए, हमें यह जानना होगा कि कितने बाइट्स "पर्याप्त नहीं थे।" यदि फ़ाइल 512 बाइट्स से कम है, तो यह 512 से इसके आकार को घटाकर निर्धारित किया जाता है। यदि यह बड़ा है, तो हम फ़ाइल के आकार को 512 से विभाजित करने के शेष को निर्धारित करते हैं, और इसे 512 से घटाते हैं। परिणाम एक बाइनरी स्ट्रिंग में पैक किया जाता है।

आपको इस बात को भी ध्यान में रखना चाहिए जब फ़ाइल शुरू में कई 512 बाइट्स की होती है - कुछ प्रोग्राम स्वतंत्र रूप से अपनी फ़ाइलों को वांछित आकार में पूरक करते हैं। बेशक, इस मामले में कुछ भी जोड़ने की जरूरत नहीं है।

यहाँ परिणामी कोड है:

$ffs = filesize($filename);
if($ffs > 512)
$tolast = 512 - fmod($ffs, 512);
else
$tolast = 512-$ffs;
if($tolast != 512 && $tolast != 0){
$fdata = pack("a".$tolast, "");
.
}


परिणाम एक टार संग्रह है। अब आप अगली फ़ाइल के साथ ऑपरेशन को दोहरा सकते हैं, या संग्रह को बंद कर सकते हैं।
अगर हमारे पास ज़्लिब लाइब्रेरी जुड़ी हुई है, तो आर्काइव बनाने की प्रक्रिया में, आप "tar.gz" या "tgz" को पाने के लिए आर्काइव को कंप्रेस कर सकते हैं। एक पुस्तकालय के लिए जाँच करने का सबसे आसान तरीका है FORCE_GZIP स्थिरांक की जाँच करना। प्रक्रिया को स्वचालित करने के लिए, मैंने संग्रह फ़ाइल के साथ सभी कार्यों के लिए इस तरह की जांच शुरू की। कुछ इस तरह:

if(defined('FORCE_GZIP'))
$resopen = @fopen($this->tarname, 'a+b');
else
$resopen = @gzopen($this->tarname, 'a+b'.$this->tarlevel);


व्यवहार में, मैं इस प्रकार भविष्य के फ़ाइल एक्सटेंशन को निर्धारित करता हूं, और पहले से ही इस पर ध्यान केंद्रित करते हुए, मैं आवश्यक कार्यों का उपयोग करता हूं, लेकिन यह महत्वपूर्ण नहीं है।

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

आप सभी हेडर को ढूंढकर और पढ़कर संग्रह की फाइलों की सूची प्राप्त कर सकते हैं। ऐसा करने के लिए, संग्रह के पहले 512 बाइट्स पढ़ें - यह हेडर वैसे भी होगा और इसे अनपैक () फ़ंक्शन के साथ अनपैक करें। चूंकि एक साहचर्य सरणी में डीकंप्रेस को अनपैक किया जाता है, उसी समय, हम मापदंडों को स्पष्ट नाम देते हैं। इस तरह:

unpack("a100name/a8perms/… …", “ ”)

निर्माण समय और आकार को वापस दशमलव में परिवर्तित किया जाना चाहिए।

प्राप्त मापदंडों को "आउटपुट पर" भेजा जा सकता है। यह केवल संग्रहित फ़ाइल में पॉइंटर को पैक्ड फ़ाइल के पढ़ने के आकार में शिफ्ट करने के लिए शेष रहता है, साथ ही शेष बचे 512-बाइट ब्लॉक के लिए। अब यह अगली हेडिंग की शुरुआत की ओर इशारा करता है, और ऑपरेशन फिर से दोहराया जा सकता है।

वांछित फ़ाइल को अनपैक करना पिछले फ़ंक्शन का उपयोग करके उसके हेडर की खोज करने के लिए कम हो जाता है, निर्दिष्ट स्थान में दिए गए नाम के साथ एक फ़ाइल बनाकर, फ़ाइल सामग्री की शुरुआत में संग्रह में फ़ाइल पॉइंटर को स्थानांतरित करना, उसकी लंबाई के अनुरूप बाइट्स की संख्या को पढ़ना और बनाई गई फ़ाइल को लिखना। निर्देशिकाओं के लिए, सब कुछ उनके निर्माण तक सीमित है।

यहाँ केवल दो कठिनाइयाँ Zlib लाइब्रेरी की विशेषताओं से संबंधित हैं:

सबसे पहले। यह पाया गया कि इस लाइब्रेरी के gzopen फ़ंक्शन में, "+" संशोधक को फ़ाइल लिखने और पढ़ने के लिए एक ही समय में, फोपेन फ़ंक्शन के समान लागू नहीं किया गया था। मुझे संग्रह फ़ाइल के एकल उद्घाटन / समापन को छोड़ना पड़ा, और प्रत्येक कार्य के साथ इन कार्यों को कार्य के अनुसार दोहराना पड़ा।

दूसरे, प्रलेखन में कहा गया है (और मैं इस संकेत की सत्यता के बारे में आश्वस्त था) कि gzseek फ़ंक्शन, fseek के समान है "अनुकरण किया जाता है, लेकिन यह बहुत धीरे-धीरे काम करता है।" मुझे संग्रह की फ़ाइल में पॉइंटर की डायरेक्ट शिफ्ट को वांछित स्थिति में छोड़ना पड़ा, इसे "खाली" पढ़ने के साथ, प्रदर्शन की रुकावट के लिए बदल दिया गया। अगर चीजें टार अभिलेखागार तक सीमित थीं, तो इससे बचा जा सकता था।

वह, वास्तव में, सब है। नतीजतन, मुझे एक पूरी तरह से सार्वभौमिक पुस्तकालय मिला, 11 के आकार का एक से अधिक असंपीड़ित कोड। आप यहां पुस्तकालय डाउनलोड कर सकते हैं: Archivator_tar-tar_gz.zip

हमेशा तुम्हारा, पंकचरपॉक

Source: https://habr.com/ru/post/In207470/


All Articles