通過PHP的Wrapper無縫遷移原有項目到新服務

來源:互聯網
上載者:User

出於效能和安全方面的考慮,公司的平台上禁用了本地檔案讀寫和對外的資料抓取.相應的,我們提供了對應的服務來做同樣的事情.新服務的介面和原來不太一樣.

專門為我們平台開發的程式當然不會存在問題,但是有大量的已有的程式和開源項目,就面臨著繁雜的遷移工作.

Wrapper
其實從PHP4.3開始,PHP就支援Wrapper了,這意味著使用者可以自訂和重載協議.

只需要使用 stream_wrapper_register 函數就可以註冊一個協議,對這個協議的相關操作,PHP都會回調相關的函數.

手冊上給了一個例子. 它註冊了一個叫var的協議,然後對這個協議操作都會回調VariableStream class裡邊定義的方法.

varname = $url["host"];
$this->position = 0;

return true;
}

function stream_read($count)
{
$ret = substr($GLOBALS[$this->varname], $this->position, $count);
$this->position += strlen($ret);
return $ret;
}

function stream_write($data)
{
$left = substr($GLOBALS[$this->varname], 0, $this->position);
$right = substr($GLOBALS[$this->varname], $this->position + strlen($data));
$GLOBALS[$this->varname] = $left . $data . $right;
$this->position += strlen($data);
return strlen($data);
}

function stream_tell()
{
return $this->position;
}

function stream_eof()
{
return $this->position >= strlen($GLOBALS[$this->varname]);
}

function stream_seek($offset, $whence)
{
switch ($whence) {
case SEEK_SET:
if ($offset < strlen($GLOBALS[$this->varname]) && $offset >= 0) {
$this->position = $offset;
return true;
} else {
return false;
}
break;

case SEEK_CUR:
if ($offset >= 0) {
$this->position += $offset;
return true;
} else {
return false;
}
break;

case SEEK_END:
if (strlen($GLOBALS[$this->varname]) + $offset >= 0) {
$this->position = strlen($GLOBALS[$this->varname]) + $offset;
return true;
} else {
return false;
}
break;

default:
return false;
}
}
}

stream_wrapper_register("var", "VariableStream")
or die("Failed to register protocol");

$myvar = "";

$fp = fopen("var://myvar", "r+");

fwrite($fp, "line1/n");
fwrite($fp, "line2/n");
fwrite($fp, "line3/n");

rewind($fp);
while (!feof($fp)) {
echo fgets($fp);
}
fclose($fp);
var_dump($myvar);

?>

回調class裡邊能實現的介面列表在這裡: http://cn2.php.net/manual/en/class.streamwrapper.php

需要注意的一些問題
建構函式
首先是,wrapper class很特別,它的建構函式並不是每次都調用的.只有在你的操作觸發了stream_open相關的操作時才會調用,比如你用file_get_contents了.而當你的操作觸發和stream無關的函數時,比如file_exists會觸發url_stat方法,這個時候建構函式是不會被調用的.

讀實現
wrapper裡邊有position和seek等概念,但是很多服務其實是一次性就讀取全部資料的,這個可以在stream_open的時候一次性讀回,放到一個屬性中,以後seek和tell的時候直接操作屬性裡邊存放的資料就可以了.

url_stat的實現
在wrapper class的實現中,url_stat的實現是個痛點.必須正確的實現url_stat才能使is_writable和is_readable等查詢檔案元資訊的函數正常工作.

而我們需要為我們的虛裝置偽造這些值.以mc為例,我給大家一些參考資料.

url_stat應該返回一個數組,分13個項,內容如下:

dev 裝置號- 寫0即可
ino inode號 – 寫0即可
mode 檔案mode – 這個是檔案的許可權控制符號,稍後詳細說明
nlink link – 寫0即可.
uid uid – Linux上用posix_get_uid可以取到,windows上為0
gid gid – Linux上用posix_get_gid可以取到,windows上為0
rdev 裝置類型 – 當為inode裝置時有值
size 檔案大小
atime 最後讀時間 格式為unix時間戳記
mtime 最後寫時間
ctime 建立時間
blksize blocksize of filesystem IO 寫零即可
blocks number of 512-byte blocks allocated 寫零即可

其中mode的值必須寫對
如果是檔案,其值為
0100000 + 檔案許可權 ; 如 0100000 + 0777;
如果是目錄,其值為
040000 + 目錄許可權 ; 如 0400000 + 0777;
可以重載標準協議
根據實際測試來看,用stream_wrapper_unregister可以卸載掉http等內建協議.這就方便我們完全無縫的替換使用者的一些操作,比如file_get_contents(‘http://sae.sina.com.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.