php接收二進位檔案怎麼替換裡面的內容

來源:互聯網
上載者:User
php接收二進位檔案如下:
header('Content-type: text/html; charset=utf-8');
error_reporting(0);
$filename = $_GET["filename"];
$filesize = $_GET["filesize"];

$xmlstr = $GLOBALS[HTTP_RAW_POST_DATA];//$_POST["data"];//
if(empty($xmlstr)) $xmlstr = file_get_contents('php://input');

$raw = $xmlstr;//得到post過來的二進位未經處理資料
$file = fopen("./upload/".$filename,"w");//開啟檔案準備寫入
fwrite($file,$raw);//寫入
fclose($file);//關閉
?>

接收的二進位檔案中非標準字元(>0x7F)的位元組被替換為三個位元組,比如E2替換為EF 9F A2
現在我想在Php接收到檔案之後還原回去,把EF 9F A2替換為E2,請問這個怎麼實現?

非常感謝!


回複討論(解決方案)

你收到的不是一個 XML 流嗎?
是文字檔而非二進位檔案呀
>0x7F 的不都是 utf-8 寬字元嗎?

你最好貼出 $raw 的內容看看

fopen("./upload/".$filename,"w b");
試試

補充
utf-8的EF 9F A2 應該是unicode F7E2 而不是 E2
且E000-F8FF屬於使用者自訂字元(就是沒有字元集以外,交給使用者使用的地區)
舉例就是某些通訊介面用自訂字元來做邊界識別

要留意這個

發送端,格式是這樣設定的:
if (xmlhttp.overrideMimeType) {
xmlhttp.overrideMimeType('text/plain; charset=x-user-defined');
} else {
xmlhttp.setRequestHeader('Accept-Charset', 'x-user-defined');
}
xmlhttp.setRequestHeader("Content-Type","application/x-www-form-urlencoded;charset=utf-8");

傳送檔案和接收檔案:

你傳送的是二進位流
按 XML 的約定,應以 base64 編碼進行傳送的
否則當做文本傳送就會有問題的

傳送時是否可以聲明為位元據,這個需要查資料

在網上找到這種方法:
XMLHttpRequest.prototype.sendAsBinary = function(datastr) {
function byteValue(x) {
return x.charCodeAt(0) & 0xff;
}
var ords = Array.prototype.map.call(datastr, byteValue);
var ui8a = new window.Uint8Array(ords);
this.send(ui8a.buffer);
}
xmlhttp.sendAsBinary(content);

在PC上用IE瀏覽器就可以。
但是我需要用在android 瀏覽器上,不支援這個函數Uint8Array,所以不知道怎麼用二進位流發送了。

比較傳送檔案和接收檔案,還是有規律的:
大於C0的加首碼為EF 9F,如E2替換為EF 9F A2
小於C0的加首碼為EF 9E,如B2替換為EF 9E B2

這樣的編碼不知道是怎麼出來的?所以想說對接收檔案的十六進位做替換,只要結果正確就行了。

有沒有什麼方法可以替換位元的?
Regex能支援嗎?

str_replace、strtr 都可以,正則也可以

$s = str_replace("\xEF\x9E\xB2", "\xB2", $s);

不過
大於C0的加首碼為EF 9F,如E2替換為EF 9F A2
的規則是什嗎?

他的資料轉換規則是這樣的:
檔案頭不變,檔案頭多長不清楚,圖上到0050h都一樣的
<=7F的位元組,因為utf-8也一樣,可以認為也轉換了utf-8
>=80的位元組,高位加上F7,再轉utf-8,例如E2就變成F7E2然後轉utf-8成為EF 9F A2

至少他圖中E2/FB/91/B2/81...都滿足這個規則

他圖示的是 sqlite 資料庫檔案,顯然資料庫中是什麼樣資料都可以存放的,位元組值 0x00 - 0xff
若能證實確如 #10 所說,那麼寫個函數就搞定了
演算法測試

$s =<<< TXT00 2D EF 8F A2 1A 05 00 00 00 01 03 EF 9F BB 0000 00 00 0E 03 EF 9F BB 02 6B 01 EF 9E 91 02 3600 EF 9E B2 01 60 00 EF 9E 81 00 EF 9E 81 00 2FTXT;$s = preg_replace("/[ \r\n]/", '', $s);$s = pack('H*', $s); //構造出位元據$m = 0;for($i=0; $i00 2D E2 1A 05 00 00 00 01 03 FB 00 00 00 00 0E   
03 FB 02 6B 01 91 02 36 00 B2 01 60 00 81 00 81
00 2F

str_replace、strtr 都可以,正則也可以

$s = str_replace("\xEF\x9E\xB2", "\xB2", $s);

不過
大於C0的加首碼為EF 9F,如E2替換為EF 9F A2
的規則是什嗎?

大於C0的加首碼為EF 9F,將EF 9F A2替換為A2+40,這個Regex怎麼寫呢?

用正則可這樣寫
假定資料已把存在變數 $s 中,則

$s = preg_replace_callback('/[\xef]../', 'foo', $s);function foo($r) {  $c = (ord($r[0]{1}) & 0x03) << 6;  $c += (ord($r[0]{2}) & 0x3f);  return chr($c);}

他圖示的是 sqlite 資料庫檔案,顯然資料庫中是什麼樣資料都可以存放的,位元組值 0x00 - 0xff
若能證實確如 #10 所說,那麼寫個函數就搞定了
演算法測試

$s =<<< TXT00 2D EF 8F A2 1A 05 00 00 00 01 03 EF 9F BB 0000 00 00 0E 03 EF 9F BB 02 6B 01 EF 9E 91 02 3600 EF 9E B2 01 60 00 EF 9E 81 00 EF 9E 81 00 2FTXT;$s = preg_replace("/[ \r\n]/", '', $s);$s = pack('H*', $s); //構造出位元據$m = 0;for($i=0; $i00 2D E2 1A 05 00 00 00 01 03 FB 00 00 00 00 0E   
03 FB 02 6B 01 91 02 36 00 B2 01 60 00 81 00 81
00 2F

另外請教下,這樣轉換的$c是字元形式列印出來,如果以十六進位寫迴文件,要怎麼處理?
我用
$raw[$j++]=$c;//raw是接收到的未經處理資料
不行,應該還要再轉換一下嗎?
我是想用$raw直接寫檔案的。

位元據中包含了很多不可列印的字元,為了直觀的看到他們,一般將其以一個位元組兩個十六進位數的格式列印出來(比如你貼圖中的軟體)

將十六進位串轉換成位元據,一般可用 pack('H*', 'ffffff')
php5.4 還提供了一個 hex2bin
echo hex2bin("6578616d706c65206865782064617461"); //example hex data

非常感謝,學習了

  • 聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.