亚洲精品久久久中文字幕-亚洲精品久久片久久-亚洲精品久久青草-亚洲精品久久婷婷爱久久婷婷-亚洲精品久久午夜香蕉

您的位置:首頁技術文章
文章詳情頁

PHP 實現(xiàn)base64編碼文件上傳出現(xiàn)問題詳解

瀏覽:82日期:2022-09-09 09:23:42

一、場景

領導:小A同學,我們要做一個樣本上傳進行分析的功能,你看下是否使用base64編碼加進去,這樣客戶端的同學就不需要用form-data方式來上傳了,直接使用json格式就可以上報,可以讓格式上報統(tǒng)一。

小A:好的,領導,馬上搞定!

咋看上面的對話沒啥問題,很多公司團隊內(nèi)部為了一些標準化的問題,都會進行一些技術選型問題,但是噩夢也就從這個對話開始,功能實現(xiàn)當然都是很簡單的,先來看簡單流程圖:

PHP 實現(xiàn)base64編碼文件上傳出現(xiàn)問題詳解

本身的流程是一個很簡單的文件轉(zhuǎn)換成base64上傳,再服務端decode保存,在開發(fā)聯(lián)調(diào)過程中沒有問題,非常完美的走下去了。

二、問題來了

突然有一天終端同學誤操作將一個37M文件上傳,nginx與php-fpm文件上傳限制均為(60M),但是在界面出現(xiàn)500錯誤,進入docker 日志查看有一條數(shù)據(jù):

Allowed memory size of 8388608 bytes exhausted (tried to allocate 1298358 bytes)

玩php的基本都知道這是啥意思,就是代碼運行過程中使用內(nèi)存超過 我們php.ini設置的memory_limit 的值,然后就屁顛屁顛進入php.ini找參數(shù)配置,很快找到:

memory_limit=128M

然后就轉(zhuǎn)念一想,不應該出現(xiàn)這個問題,我們知道,php的內(nèi)部變量使用cow(寫時復制)機制來實現(xiàn),那么內(nèi)存申請只有在變量賦值變更才會進行

三、測驗

接下來我們單獨寫一個程序來進行測試,將一個4.89M文件進行base64_encode 編碼 與base64_decode解碼,查看各自占用內(nèi)存以及過程中占用峰值內(nèi)存

<?php$mid = memory_get_usage();$apk_content = file_get_contents(__DIR__ . ’/4bc1c8a05b8505662be778b6dad23b55.apk’);var_dump(’文件加載到內(nèi)存:’ . round((memory_get_usage() - $mid) / 1024 / 1024, 2) . ’M’);var_dump(’過程中峰值使用的內(nèi)存:’ . round(memory_get_peak_usage() / 1024 / 1024, 2) . ’M’);unset($mid);$mid = memory_get_usage();$base64_encode = base64_encode($apk_content);unset($apk_content);var_dump(’base64_encode占用內(nèi)存:’ . round((memory_get_usage() - $mid) / 1024 / 1024, 2) . ’M’);var_dump(’過程中峰值使用的內(nèi)存:’ . round(memory_get_peak_usage() / 1024 / 1024, 2) . ’M’);unset($mid);$mid = memory_get_usage();base64_decode($base64_encode);var_dump(’base64_decode占用內(nèi)存:’ . round((memory_get_usage() - $mid) / 1024 / 1024, 2) . ’M’);var_dump(’過程中峰值使用的內(nèi)存:’ . round(memory_get_peak_usage() / 1024 / 1024, 2) . ’M’);unset($mid);

執(zhí)行結(jié)果:

string(29) '文件加載到內(nèi)存:4.89M'string(38) '過程中峰值使用的內(nèi)存:5.25M'string(33) 'base64_encode占用內(nèi)存:1.63M'string(39) '過程中峰值使用的內(nèi)存:11.76M'string(30) 'base64_decode占用內(nèi)存:0M'string(38) '過程中峰值使用的內(nèi)存:13.4M'

通過上面結(jié)果可以看出

加載文件使用內(nèi)存沒有太大問題,加載過程使用的峰值在5.25M,高出整體文件大小不多,這在文件加載過程有一些臨時申請內(nèi)存的問題 base64_encode占用內(nèi)存,這個在使用的時候,就已經(jīng)將內(nèi)存差不多進行一個double,而這基本上也是在內(nèi)核解析過程中,進行了內(nèi)存申請,可以理解,文件本身占用內(nèi)存+base64_encode 解析后的內(nèi)存,兩份內(nèi)存同時存在的 base64_decode操作,這個操作就是解密了,解密過程中,這里直接就占用了3倍多的內(nèi)存操作,問題就出在這里,在場景中出現(xiàn)的問題是一個37M的文件,為什么就把單個fpm的128M內(nèi)存占滿了呢

四、源碼解析

base64_encode源碼解析

首先找到對應的c文件 base64.c,找到里面php_base64_encode函數(shù)

PHPAPI zend_string *php_base64_encode(const unsigned char *str, size_t length) /* {{{ */{const unsigned char *current = str;unsigned char *p;zend_string *result;result = zend_string_safe_alloc(((length + 2) / 3), 4 * sizeof(char), 0, 0);p = (unsigned char *)ZSTR_VAL(result); ...}

我們先來分析這段代碼,因為這里涉及到內(nèi)存的問題,那么我們就看

result = zend_string_safe_alloc(((length + 2) / 3), 4 * sizeof(char), 0, 0);

這啥意思呢?

申請內(nèi)存,最終調(diào)用的函數(shù)是:

safe_emalloc(size_t nmemb, size_t size, size_t offset)

在wiki上解釋是:

void *safe_emalloc(size_t nmemb, size_t size, size_t offset)分配緩沖區(qū)來存放每塊大小為 size 字節(jié)的 nmemb 塊,并附加 offset 字節(jié)。類似于 emalloc(nmemb * size + offset),但增加了針對溢出的特殊保護。

那么我可以簡單的認為,就是在encode過程中,重新申請了內(nèi)存,申請的內(nèi)存大小是文件本身的 4/3 大小,加上原來的文件本身大小,那么峰值大小可以理解為

峰值內(nèi)存= 7/3 *4.89 = 11.41

那么與我們實驗過程中峰值大小基本是相符。

base64_decode操作

同樣我們進行源碼分析

PHPAPI zend_string *php_base64_decode_ex(const unsigned char *str, size_t length, zend_bool strict) /* {{{ */{const unsigned char *current = str;int ch, i = 0, j = 0, padding = 0;zend_string *result;result = zend_string_alloc(length, 0);...}

這里使用的zend_string_alloc來進行申請內(nèi)存,那么底層使用的函數(shù)就是emalloc函數(shù),來看下wiki的解釋

void *emalloc(size_t size)分配 size 字節(jié)的內(nèi)存。

這個就比較好理解了,傳入?yún)?shù)內(nèi)存再進行一個double拷貝就可以,

那么我們進行一個decode的內(nèi)存峰值的計算:

峰值內(nèi)存=(4/3+4/3) *4.89 =13.04

基本與我們測試的結(jié)果相差不多,因為精度關系,我們進行四舍五入的計算,測試代碼是精準計算,所以會有小數(shù)點偏差。

五、總結(jié)

那這就可以理解為什么一個為什么在我們一個37M的文件,不能再128M內(nèi)存進行base64_encode與base64_decode操作,當然這里有一些臨時變量沒有及時釋放內(nèi)存的情況,但是通過源碼分析可以知道,要做一次這樣場景來進行文件上傳,單純文件的內(nèi)存損耗是2.6倍左右,所以為了節(jié)省內(nèi)存,我們不要再用這個方式來進行操作了,很費內(nèi)存的

以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持好吧啦網(wǎng)。

標簽: PHP
相關文章:
主站蜘蛛池模板: 一区二区在线视频免费观看 | 天天躁夜夜躁很很躁2020 | 国产精品久久影院 | 91在线播放国产 | 亚洲一区二区精品推荐 | 国产精品永久在线 | 91华人在线视频 | 中文字幕一区二区在线观看 | 精品国产91久久久久 | 国产91av在线 | 国产色视频在线观看免费 | 久久久久亚洲 | 亚洲欧美日韩一区二区 | 亚洲精品成人一区 | 黄色大片免费在线观看 | 七色永久性tv网站免费看 | 成人看片毛片免费播放器 | 精品国产自在现线久久 | 国产免费一级片 | 国产欧美日韩亚洲精品区2345 | 综合久久精品 | 欧美三级在线观看黄 | 性视频网站在线 | 男女交性粗大视频播放 | 国产美女挤奶水在线观看 | 国产一区二区三区亚洲欧美 | 欧美三级成人观看 | 成人在线观看免费爱爱 | 欧美成人精品第一区二区三区 | japanese国产高清麻豆 | pr社萌汁福利视频在线观看 | 国产日韩在线观看视频 | 欧美毛片在线播放观看 | 国产最强大片免费视频 | 黄色视屏免费观看 | 成年美女毛片黄网站色奶头大全 | 一级毛片免费观看 | 日韩免费高清一级毛片 | 成人短视频在线在线观看 | 在线免费观看色 | a级黄色网址|