电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

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

PHP 實現base64編碼文件上傳出現問題詳解

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

一、場景

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

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

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

PHP 實現base64編碼文件上傳出現問題詳解

本身的流程是一個很簡單的文件轉換成base64上傳,再服務端decode保存,在開發聯調過程中沒有問題,非常完美的走下去了。

二、問題來了

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

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

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

memory_limit=128M

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

三、測驗

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

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

執行結果:

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

通過上面結果可以看出

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

四、源碼解析

base64_encode源碼解析

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

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); ...}

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

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

這啥意思呢?

申請內存,最終調用的函數是:

safe_emalloc(size_t nmemb, size_t size, size_t offset)

在wiki上解釋是:

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

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

峰值內存= 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來進行申請內存,那么底層使用的函數就是emalloc函數,來看下wiki的解釋

void *emalloc(size_t size)分配 size 字節的內存。

這個就比較好理解了,傳入參數內存再進行一個double拷貝就可以,

那么我們進行一個decode的內存峰值的計算:

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

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

五、總結

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

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

標簽: PHP
相關文章:
主站蜘蛛池模板: 游泳池设计|设备|配件|药品|吸污机-东莞市太平洋康体设施有限公司 | 高精度电阻回路测试仪-回路直流电阻测试仪-武汉特高压电力科技有限公司 | ETFE膜结构_PTFE膜结构_空间钢结构_膜结构_张拉膜_浙江萬豪空间结构集团有限公司 | 碳化硅,氮化硅,冰晶石,绢云母,氟化铝,白刚玉,棕刚玉,石墨,铝粉,铁粉,金属硅粉,金属铝粉,氧化铝粉,硅微粉,蓝晶石,红柱石,莫来石,粉煤灰,三聚磷酸钠,六偏磷酸钠,硫酸镁-皓泉新材料 | 曙光腾达官网-天津脚手架租赁-木板架出租-移动门式脚手架租赁「免费搭设」 | 高博医疗集团上海阿特蒙医院 | 沈飞防静电地板__机房地板-深圳市沈飞防静电设备有限公司 | 纳米二氧化硅,白炭黑,阴离子乳化剂-臻丽拾科技| 山东彩钢板房,山东彩钢活动房,临沂彩钢房-临沂市贵通钢结构工程有限公司 | 制冷采购电子商务平台——制冷大市场 | 涂层测厚仪_光泽度仪_uv能量计_紫外辐照计_太阳膜测试仪_透光率仪-林上科技 | 雷达液位计_超声波风速风向仪_雨量传感器_辐射传感器-山东风途物联网 | 刑事律师_深圳著名刑事辩护律师_王平聚【清华博士|刑法教授】 | 飞行者联盟-飞机模拟机_无人机_低空经济_航空技术交流平台 | 山东钢衬塑罐_管道_反应釜厂家-淄博富邦滚塑防腐设备科技有限公司 | HYDAC过滤器,HYDAC滤芯,现货ATOS油泵,ATOS比例阀-东莞市广联自动化科技有限公司 | 组织研磨机-高通量组织研磨仪-实验室多样品组织研磨机-东方天净 传递窗_超净|洁净工作台_高效过滤器-传递窗厂家广州梓净公司 | 吹塑加工_大型吹塑加工_滚塑代加工-莱力奇吹塑加工有限公司 | 恒压供水控制柜|无负压|一体化泵站控制柜|PLC远程调试|MCGS触摸屏|自动控制方案-联致自控设备 | 开云(中国)Kaiyun·官方网站 - 登录入口 | 科研ELISA试剂盒,酶联免疫检测试剂盒,昆虫_植物ELISA酶免试剂盒-上海仁捷生物科技有限公司 | 河南橡胶接头厂家,河南波纹补偿器厂家,河南可曲挠橡胶软连接,河南套筒补偿器厂家-河南正大阀门 | 地图标注|微信高德百度地图标注|地图标记-做地图[ZuoMap.com] | 变频器维修公司_plc维修_伺服驱动器维修_工控机维修 - 夫唯科技 变位机,焊接变位机,焊接变位器,小型变位机,小型焊接变位机-济南上弘机电设备有限公司 | 车件|铜件|车削件|车床加工|五金冲压件-PIN针,精密车件定制专业厂商【东莞品晔】 | 耐驰泵阀管件制造-耐驰泵阀科技(天津)有限公司 | 泵阀展|阀门展|水泵展|流体机械展 -2025上海国际泵管阀展览会flowtech china | 温控器生产厂家-提供温度开关/热保护器定制与批发-惠州市华恺威电子科技有限公司 | 哈希余氯测定仪,分光光度计,ph在线监测仪,浊度测定仪,试剂-上海京灿精密机械有限公司 | 中国产业发展研究网 - 提供行业研究报告 可行性研究报告 投资咨询 市场调研服务 | 膜结构车棚|上海膜结构车棚|上海车棚厂家|上海膜结构公司 | 润滑油加盟_润滑油厂家_润滑油品牌-深圳市沃丹润滑科技有限公司 琉璃瓦-琉璃瓦厂家-安徽盛阳新型建材科技有限公司 | 自动气象站_气象站监测设备_全自动气象站设备_雨量监测站-山东风途物联网 | 超声波清洗机_大型超声波清洗机_工业超声波清洗设备-洁盟清洗设备 | 在线钠离子分析仪-硅酸根离子浓度测定仪-油液水分测定仪价格-北京时代新维测控设备有限公司 | 空压机网_《压缩机》杂志 | 六维力传感器_六分量力传感器_模腔压力传感器-南京数智微传感科技有限公司 | 北京网络营销推广_百度SEO搜索引擎优化公司_网站排名优化_谷歌SEO - 北京卓立海创信息技术有限公司 | 氧化锆陶瓷_氧化锆陶瓷加工_氧化锆陶瓷生产厂家-康柏工业陶瓷有限公司 | 哈希PC1R1A,哈希CA9300,哈希SC4500-上海鑫嵩实业有限公司 | 聚合氯化铝价格_聚合氯化铝厂家_pac絮凝剂-唐达净水官网 |