摘要:第行通過(guò)類(lèi)提供的方法分別獲取本類(lèi)和父類(lèi)中的屬性,然后進(jìn)行對(duì)比剔除父類(lèi)的屬性,保留本類(lèi)的屬性,此方法返回的是一個(gè)類(lèi)對(duì)象。
前言
上個(gè)星期碰到個(gè)客戶(hù)使用Swoole Compiler加密Drupal導(dǎo)致Drupal項(xiàng)目無(wú)法運(yùn)行的問(wèn)題,逐步排查后總結(jié)問(wèn)題是Drupal中有部分代碼直接通過(guò)file_get_contents獲取PHP源碼導(dǎo)致的,因?yàn)轫?xiàng)目代碼是加密過(guò)后的,所以直接獲取PHP源碼解析是獲取不到想要的內(nèi)容的。
注:
Swoole Compiler:https://www.swoole-cloud.com/compiler.html
Drupal是使用PHP語(yǔ)言編寫(xiě)的開(kāi)源內(nèi)容管理框架(CMF),它由內(nèi)容管理系統(tǒng)(CMS)和PHP開(kāi)發(fā)框架(Framework)共同構(gòu)成。
加密后的影響Drupal運(yùn)行的主要代碼 代碼路徑drupal/vendor/doctrine/common/lib/Doctrine/Common/Reflection/StaticReflectionParser.php:126
//代碼內(nèi)容 protected function parse() { if ($this->parsed || !$fileName = $this->finder->findFile($this->className)) { return; } $this->parsed = true; $contents = file_get_contents($fileName); if ($this->classAnnotationOptimize) { if (preg_match("/A.*^s*((abstract|final)s+)?classs+{$this->shortClassName}s+/sm", $contents, $matches)) { $contents = $matches[0]; } } $tokenParser = new TokenParser($contents); ...... }
其中部分代碼如上,通過(guò)class名獲取文件路徑,然后通過(guò)file_get_contents獲取PHP文件的內(nèi)容,其中TokenParser類(lèi)中構(gòu)造函數(shù)如下
public function __construct($contents) { $this->tokens = token_get_all($contents); token_get_all("numTokens = count($this->tokens); }
傳入獲取到的源碼通過(guò)token_get_all進(jìn)行解析,然后后續(xù)分析代碼獲取PHP文件的類(lèi)、屬性、方法的注釋 ,父類(lèi)的命名空間 和class名 ,本類(lèi)的use信息等,因?yàn)槲募呀?jīng)加密,所以file_get_contents獲取到的內(nèi)容是加密后的內(nèi)容,token_get_all就解析不到正確的信息,從而導(dǎo)致程序無(wú)法運(yùn)行。
解決方案本次使用的2.1.1版本的加密器,通過(guò)Swoole Compiler加密器加密的代碼,在配置文件中save_doc配置選項(xiàng)必須設(shè)置為1,如果設(shè)置為0則不會(huì)保存注釋?zhuān)⑶以?b>2.1.3版本swoole_loader.so擴(kuò)展中新增加的函數(shù)naloinwenraswwww也無(wú)法獲取到類(lèi)中use的相關(guān)信息,具體函數(shù)使用在后面會(huì)詳細(xì)說(shuō)明。
1 $ref = new ReflectionClass($this->className); 2 3 $parent_ref = $ref->getParentClass(); 4 5 ...... 6 7 if (is_file($fileName)) { 8 $php_file_info = unserialize(naloinwenraswwww(realpath($fileName))); 9 foreach ($php_file_info as $key => $info) { 10 if ($key == "swoole_namespaces" || $key == "swoole_class_name") { 11 continue; 12 } 13 $this->useStatements[$key] = $info; 14 } 15 } 16 17 $this->parentClassName = $parent_ref->getName(); 18 19 if (strpos($this->parentClassName, "")!==0) { 20 $this->parentClassName = "".$this->parentClassName; 21 } 22 23 $static_properties = []; 24 25 $properties = $ref->getProperties(); 26 27 $parent_properties = $this->createNewArrKey($parent_ref->getProperties()); 28 29 ...... 30 31 $static_methods = []; 32 33 $methods = $ref->getMethods(); 34 35 ......
第1行通過(guò)類(lèi)名來(lái)獲取反射類(lèi)ReflectionClass類(lèi)的對(duì)象。
因?yàn)榇朔瓷漕?lèi)包含了所有父類(lèi)中的屬性和方法,但源碼中只要獲取本類(lèi)中的屬性和方法,所以還要獲取父類(lèi)的反射類(lèi)然后通過(guò)對(duì)比來(lái)剔除父類(lèi)中的屬性和方法,第3行使用ReflectionClass類(lèi)提供的getParentClass方法獲取父類(lèi)的反射類(lèi),此方法返回父類(lèi)的ReflectionClass對(duì)象。
第25行通過(guò)ReflectionClass類(lèi)提供的getProperties方法分別獲取本類(lèi)和父類(lèi)中的屬性,然后進(jìn)行對(duì)比剔除父類(lèi)的屬性,保留本類(lèi)的屬性,此方法返回的是一個(gè)ReflectionProperty類(lèi)對(duì)象。
通過(guò)ReflectionProperty類(lèi)提供的getDocComment方法就可以拿到屬性的注釋。
同上第33行通過(guò)ReflectionClass類(lèi)提供的getMethods方法可以拿到本類(lèi)和父類(lèi)中的方法,然后進(jìn)行對(duì)比剔除父類(lèi)的方法,保留本類(lèi)的方法,此方法返回的是一個(gè)ReflectionMethod類(lèi)對(duì)象。
通過(guò)ReflectionMethod對(duì)象提供的getDocComment方法就可以拿到方法的注釋。
通過(guò)第17行ReflectionClass提供的getName方法可以拿到類(lèi)名。
因?yàn)榉瓷錈o(wú)法獲取use類(lèi)的信息,所以在2.1.3版本中的swoole_loader.so擴(kuò)展中添加函數(shù)naloinwenraswwww,此函數(shù)傳入一個(gè)PHP文件的絕對(duì)路徑,返回傳入文件的相關(guān)信息的序列化數(shù)組,反序列化后數(shù)組如下
[ "swoole_namespaces" => "DrupalCoreDatetimeElement", "swoole_class_name" => "DrupalCoreDatetimeElementDateElementBase", "nestedarray" => "DrupalComponentUtilityNestedArray", "drupaldatetime" => "DrupalCoreDatetimeDrupalDateTime", "formelement"=> "DrupalCoreRenderElementFormElement" ]
其中swoole_namespaces為文件的命名空間,swoole_class_name為文件的命名空間加類(lèi)名,其他為use信息,鍵為use類(lèi)的類(lèi)名小寫(xiě)字母,如存在別名則為別名的小寫(xiě)字母,值為use類(lèi)的命名空間加類(lèi)名,通過(guò)該函數(shù)和反射函數(shù)可以兼容StaticReflectionParser中加密后出現(xiàn)的無(wú)法獲取正確信息的問(wèn)題
在加密后的未影響Drupal運(yùn)行的潛在問(wèn)題:代碼路徑:drupal/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/PhpParser.php:39
代碼路徑:drupal/vendor/symfony/class-loader/ClassMapGenerator.php:91
代碼路徑:drupal/vendor/symfony/routing/Loader/AnnotationFileLoader.php:90
Drupal中引入了Symfony框架,此框架中部分代碼也是通過(guò)file_get_contents和token_get_all來(lái)獲取PHP文件的類(lèi)名,但目前未對(duì)Druapl運(yùn)行產(chǎn)生影響,可能并未用到其中方法解決方案:
同StaticReflectionParser類(lèi)的解決方案一樣通過(guò)2.1.3版本中的swoole_loader.so擴(kuò)展中添加函數(shù)naloinwenraswwww來(lái)獲取加密后文件的命名空間和類(lèi)名
尚未有更好方案的問(wèn)題:代碼路徑:drupal/core/includes/install.inc:220
function drupal_rewrite_settings($settings = [], $settings_file = NULL) { if (!isset($settings_file)) { $settings_file = Drupal::service("site.path") . "/settings.php"; } // Build list of setting names and insert the values into the global namespace. $variable_names = []; $settings_settings = []; foreach ($settings as $setting => $data) { if ($setting != "settings") { _drupal_rewrite_settings_global($GLOBALS[$setting], $data); } else { _drupal_rewrite_settings_global($settings_settings, $data); } $variable_names["$" . $setting] = $setting; } $contents = file_get_contents($settings_file); if ($contents !== FALSE) { // Initialize the contents for the settings.php file if it is empty. if (trim($contents) === "") { $contents = " $setting) { $buffer .= _drupal_rewrite_settings_dump($setting, "$" . $name); } // Write the new settings file. if (file_put_contents($settings_file, $buffer) === FALSE) { throw new Exception(t("Failed to modify %settings. Verify the file permissions.", ["%settings" => $settings_file])); } else { // In case any $settings variables were written, import them into the // Settings singleton. if (!empty($settings_settings)) { $old_settings = Settings::getAll(); new Settings($settings_settings + $old_settings); } // The existing settings.php file might have been included already. In // case an opcode cache is enabled, the rewritten contents of the file // will not be reflected in this process. Ensure to invalidate the file // in case an opcode cache is enabled. OpCodeCache::invalidate(DRUPAL_ROOT . "/" . $settings_file); } } else { throw new Exception(t("Failed to open %settings. Verify the file permissions.", ["%settings" => $settings_file])); } }
Drupal安裝過(guò)程中有個(gè)配置文件default.setting.php,里面存放了默認(rèn)配置數(shù)組,在安裝的過(guò)程中會(huì)讓用戶(hù)在安裝界面輸入一些配置比如Mysql的信息,輸入過(guò)后此方法通過(guò)file_get_contents和token_get_all來(lái)獲取setting中的信息,然后合并用戶(hù)在頁(yè)面輸入的信息,重新存回文件,因?yàn)檎麄€(gè)過(guò)程涉及到讀取文件,更改文件信息,在存入文件,所以Swoole Compiler在此處暫時(shí)沒(méi)有更好的解決方案,需要在加密的時(shí)候選擇不加密setting文件。
代碼路徑:drupal/vendor/symfony/class-loader/ClassCollectionLoader.php:126
此類(lèi)中是Symfony讀取PHP文件然后作相應(yīng)處理后緩存到文件中,存在和上面代碼同樣的問(wèn)題,暫未找到更好的解決方案
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/31592.html
摘要:通過(guò)類(lèi)提供的方法分別獲取本類(lèi)和父類(lèi)中的屬性,然后進(jìn)行對(duì)比剔除父類(lèi)的屬性,保留本類(lèi)的屬性,此方法返回的是一個(gè)類(lèi)對(duì)象。 問(wèn)題描述 上個(gè)星期碰到個(gè)客戶(hù)使用swoole compiler加密drupal導(dǎo)致drupal項(xiàng)目無(wú)法運(yùn)行的問(wèn)題,逐步排查后總結(jié)問(wèn)題是drupal中有部分代碼直接通過(guò)file_get_contents獲取php源碼導(dǎo)致的,因?yàn)轫?xiàng)目代碼是加密過(guò)后的,所以直接獲取php源碼解...
摘要:偏巧的是重定向的過(guò)程會(huì)給黑客提供中間人攻擊。在上例的情況下,從發(fā)送頭部到得到響應(yīng),有效性可保持年。它認(rèn)為這個(gè)頭部可以預(yù)防偽造跨站請(qǐng)求??偨Y(jié)使用以上頭部可幫你快速容易地預(yù)防攻擊點(diǎn)擊挾持攻擊嗅探和中間人攻擊。請(qǐng)確保用戶(hù)的安全性。 它曾是世界性圖書(shū)館夢(mèng)的開(kāi)始,現(xiàn)在它是全球知識(shí)的聚集地,它是目前最流行的,人們將應(yīng)用都部署之上的萬(wàn)維網(wǎng)。 它是敏捷的代表,它不是單一的實(shí)體,它由客戶(hù)端和服務(wù)端組成...
摘要:另一方比如小明得到公鑰之后,雙方就可以通信。然而,中間人還是可能截獲公鑰,然后自己弄一對(duì)秘鑰,然后告訴小明說(shuō)是小紅的公鑰。這樣,小亮在簽署小紅的身份證的時(shí)候,可以在小紅身份證后面附上自己的身份證。一般來(lái)說(shuō),自簽名的根身份證用于公司內(nèi)部使用。 前言 自從 Lets Encrypt 上線之后,HTTPS 網(wǎng)站數(shù)量占比越來(lái)越高,相信不久的未來(lái)就可以實(shí)現(xiàn)全網(wǎng) HTTPS,大部分主流瀏覽器也對(duì) ...
閱讀 1010·2023-04-25 15:42
閱讀 3604·2021-11-02 14:38
閱讀 2896·2021-09-30 09:48
閱讀 1437·2021-09-23 11:22
閱讀 3399·2021-09-06 15:02
閱讀 3195·2021-09-04 16:41
閱讀 613·2021-09-02 15:41
閱讀 2025·2021-08-26 14:13