詳解PHP資料壓縮、加解密(pack, unpack)

來源:互聯網
上載者:User
網路通訊、檔案儲存體中經常需要交換資料,為了減少網路通訊流量、檔案儲存體大小以及加密通訊規則,經常需要對資料進行雙向加解密以保證資料的安全。
PHP中實現此功能主要需要使用的函數主要是pack及unpack函數

pack
壓縮資料到位字串之中。
文法: string pack(string format, mixed [args]...);
傳回值: 字串
本函數用來將資料壓縮打包到位的字串之中。
a - NUL- 字串填滿[padded string] 將字串空白以 NULL 字元填滿
A - SPACE- 字串填滿[padded string]
h – 十六進位字串,低“四位元”[low nibble first] (低位在前)
H - 十六進位字串,高“四位元”[high nibble first](高位在前)
c – 帶有符號的字元
C – 不帶有符號的字元
s – 帶有符號的短模式[short](通常是16位,按機器位元組順序)
S – 不帶有符號的短模式[short](通常是16位,按機器位元組排序)
n -不帶有符號的短模式[short](通常是16位,按大endian位元組排序)
v -不帶有符號的短模式[short](通常是16位,按小endian位元組排序)
i – 帶有符號的整數(由大小和位元組順序決定)
I – 不帶有符號的整數(由大小和位元組順序決定)
l– 帶有符號的長模式[long](通常是32位,按機器位元組順序)
L – 不帶有符號的長模式[long](通常是32位,按機器位元組順序)
N – 不帶有符號的長模式[long](通常是32位,按大edian位元組順序)
V– 不帶有符號的長模式[long](通常是32位,按小edian位元組順序)
f –浮點(由大小和位元組順序決定)
d – 雙精確度(由大小和位元組順序決定)
x – 空位元組[NUL byte]
X- 後面一個位元組[Back up one byte](倒回一位)

unpack
解壓縮位字串資料。
文法: string pack(string format, mixed [args]...);
傳回值: 數組
本函數用來將位的字串的資料解壓縮。本函數和 Perl 的同名函數功能用法完全相同。

案例一、pack實現縮減檔案資料存放區大小

<?php //儲存整數1234567890 file_put_contents("test.txt", 1234567890);

此時test.txt的檔案大小是10byte。注意此時檔案大小是10位元組,實際佔用空間大小是1KB。
上面儲存的整數實際是以字串形式儲存於檔案test.txt中。
但如果以整數的二進位字串存jy儲,將會縮減至4byte。

<?php print_r(unpack("i", file_get_contents("test.txt")));


案例二、資料加密
以字串形式儲存一段有意義資料,7-110-abcdefg-117。
字元"-"分割後,第一位表示字串長度,第二位表示儲存位置,第三位表示實際儲存的字串,第四位表示結尾位置。

<?php file_put_contents("test.txt", "7-110-abcdefg-117");

上述方法缺點:
一、資料存放區大小
二、資料以明文方式儲存,如果是任何敏感資訊,都可能造成不安全訪問。
三、檔案儲存體大小,以不規則方式遞增。
加密:

<?php file_put_contents("test.txt", pack("i2a7i1", 7, 110, "abcdefg", 117));

儲存一段資料,加密格式為:整數2位長度字串10位長度整數1位長度。
優點:
一、資料大小最佳化
二、在不知道"i2a7i1"這樣的壓縮格式時,即使拿到檔案,也無法正確讀出二進位檔案轉化為明文。
三、資料增加時,檔案儲存體大小是等量遞增。每次都是以19byte遞增。

案例三、key-value型檔案儲存體
儲存產生的檔案為兩個:索引檔案,資料檔案
檔案中資料存放區的格式如:


代碼實現:

<?php error_reporting(E_ALL);  class fileCacheException extends Exception{  }  //Key-Value型檔案儲存體 class fileCache{    private $_file_header_size = 14;    private $_file_index_name;    private $_file_data_name;    private $_file_index;//索引檔案控制代碼    private $_file_data;//資料檔案控制代碼    private $_node_struct;//索引結點結構體    private $_inx_node_size = 36;//索引結點大小     public function __construct($file_index="filecache_index.dat", $file_data="filecache_data.dat"){      $this->_node_struct = array(         'next'=>array(1, 'V'),         'prev'=>array(1, 'V'),        'data_offset'=>array(1,'V'),//資料存放區起始位置        'data_size'=>array(1,'V'),//資料長度        'ref_count'=>array(1,'V'),//引用此處,模仿PHP的引用計數銷毀模式        'key'=>array(16,'H*'),//儲存KEY      );       $this->_file_index_name = $file_index;      $this->_file_data_name = $file_data;       if(!file_exists($this->_file_index_name)){         $this->_create_index();      }else{         $this->_file_index = fopen($this->_file_index_name, "rb+");      }       if(!file_exists($this->_file_data_name)){         $this->_create_data();      }else{         $this->_file_data = fopen($this->_file_data_name, "rb+");//二進位儲存需要使用b      }    }     //建立索引檔案    private function _create_index(){      $this->_file_index = fopen($this->_file_index_name, "wb+");//二進位儲存需要使用b      if(!$this->_file_index)          throw new fileCacheException("Could't open index file:".$this->_file_index_name);       $this->_index_puts(0, '<'.'?php exit()?'.'>');//定位檔案流至起始位置0, 放置php標記防止下載      $this->_index_puts($this->_file_header_size, pack("V1", 0));    }      //建立隱藏檔    private function _create_data(){      $this->_file_data = fopen($this->_file_data_name, "wb+");//二進位儲存需要使用b      if(!$this->_file_index)          throw new fileCacheException("Could't open index file:".$this->_file_data_name);       $this->_data_puts(0, '<'.'?php exit()?'.'>');//定位檔案流至起始位置0, 放置php標記防止下載    }     private function _index_puts($offset, $data, $length=false){      fseek($this->_file_index, $offset);       if($length)      fputs($this->_file_index, $data, $length);      else      fputs($this->_file_index, $data);    }     private function _data_puts($offset, $data, $length=false){      fseek($this->_file_data, $offset);      if($length)      fputs($this->_file_data, $data, $length);      else      fputs($this->_file_data, $data);    }     /**    * 檔案鎖    * @param $is_block 是否獨佔、阻塞鎖    */    private function _lock($file_res, $is_block=true){      flock($file_res, $is_block ? LOCK_EX : LOCK_EX|LOCK_NB);    }     private function _unlock($file_res){      flock($file_res, LOCK_UN);    }     public function add($key, $value){      $key = md5($key);      $value = serialize($value);      $this->_lock($this->_file_index, true);      $this->_lock($this->_file_data, true);       fseek($this->_file_index, $this->_file_header_size);       list(, $index_count) = unpack('V1', fread($this->_file_index, 4));       $data_size = filesize($this->_file_data_name);       fseek($this->_file_data, $data_size);       $value_size = strlen($value);       $this->_data_puts(filesize($this->_file_data_name), $value);       $node_data =       pack("V1V1V1V1V1H32", ($index_count==0) ? 0 : $index_count*$this->_inx_node_size, 0, filesize($this->_file_data_name), strlen($value), 0, $key);       $index_count++;       $this->_index_puts($this->_file_header_size, $index_count, 4);       $this->_index_puts($this->get_new_node_pos($index_count), $node_data);       $this->_unlock($this->_file_data);      $this->_unlock($this->_file_index);    }     public function get_new_node_pos($index_count){      return $this->_file_header_size + 4 + $this->_inx_node_size * ($index_count-1);    }     public function get_node($key){      $key = md5($key);      fseek($this->_file_index, $this->_file_header_size);      $index_count = fread($this->_file_index, 4);       if($index_count>0) {         for ($i=0; $i < $index_count ; $i++) {            fseek($this->_file_index, $this->_file_header_size + 4 + $this->_inx_node_size * $i);           $data = fread($this->_file_index, $this->_inx_node_size);           $node = unpack("V1next/V1prev/V1data_offset/V1data_size/V1ref_count/H32key", $data);            if($key == $node['key']){              return $node;           }         }      }else{         return null;      }    }     public function get_data($offset, $length){      fseek($this->_file_data, $offset);      return unserialize(fread($this->_file_data, $length));    } }  //使用方法 $cache = new fileCache(); $cache->add('abcdefg' , 'testabc'); $data = $cache->get_node('abcdefg'); print_r($data); echo $cache->get_data($data['data_offset'], $data['data_size']);

案例四、socket通訊加密
通訊雙方都定義好加密格式:
例如:

$LOGIN = array(    'COMMAND'=>array('a30', 'LOGIN'),    'DATA'=>array('a30', 'HELLO') );  $LOGOUT = array(    'COMMAND'=>array('a30', 'LOGOUT'),    'DATA'=>array('a30', 'GOOD BYE') );  $LOGIN_SUCCESS = array(    'COMMAND'=>array('a30', 'LOGIN_SUCCESS'),    'DATA'=>array('V1', 1) );  $LOGOUT_SUCCESS = array(    'COMMAND'=>array('a30', 'LOGIN_SUCCESS'),    'DATA'=>array('V1', time()) );

伺服器端與用戶端根據解析COMMAND格式,找到對應的DATA解碼方式,得到正確的資料

以上就是詳解PHP資料壓縮、加解密(pack, unpack) 的內容,更多相關內容請關注topic.alibabacloud.com(www.php.cn)!

  • 聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.