iT邦幫忙

2021 iThome 鐵人賽

DAY 16
0
Software Development

用 PHP 打造專屬於自己的 Telegram 聊天機器人吧!系列 第 16

【PHP Telegram Bot】Day16 - 基礎(5):檔案讀取與寫入、cURL

對程式來說,檔案的處理與網絡傳輸是差不多的,所以會有一些兩者都通用的函式

內建函式

最主要就是這兩個函式:

  • file_get_contents() 讀取
  • file_put_contents() 寫入

這兩個函式是其他一堆函式經過包裝後的,所以用起來非常的輕鬆容易

$file = 'data.txt';
// 讀取檔案
$current = file_get_contents($file);
// 修改內容
$current .= "增加一些內容\n";
// 寫入檔案
file_put_contents($file, $current, LOCK_EX);
// LOCK_EX 可以避免寫入時被存取
$file = 'data.txt';
$current = "增加一些內容";
// 寫入檔案
file_put_contents($file, $current, FILE_APPEND | LOCK_EX);
// FILE_APPEND 可以寫入新的一行

但是會遇到一個很常見的問題,而且這兩個函式無法處理

競爭危害 Race Condition

  1. A 讀取檔案
  2. B 讀取檔案
  3. A 增加一些內容
  4. B 增加一些內容
  5. A 寫入檔案
  6. B 寫入檔案

這樣就造成了檔案裡只剩下 B 增加的內容,所以接下來要介紹其他的內建函式

其他內建函式:

函式 說明 用法
mkdir() 新增目錄(資料夾) mkdir($path)
unlink() 刪除檔案 unlink($path)
rmdir() 刪除目錄(資料夾) rmdir($path)
rename() 重新命名檔案或目錄 rename($old_path, $new_path)
file_exists() 檢查檔案或目錄是否存在 file_exists($path)
is_dir() 檢查是否為目錄 is_dir($path)
is_file() 檢查是否為檔案 is_file($path)
filesize() 檔案的大小 filesize($path)
fopen() 開啟檔案 fopen($path, $mode)
flock() 鎖定檔案 flock($fp, $option)
ftruncate() 截斷檔案(刪除大於設定的內容) ftruncate($fp, $size)
rewind() 將檔案的指標位置移至檔頭 rewind($fp)
ftell() 返回指標位置 ftell($fp)
fseek() 移動指標位置 fseek($fp, $pos);
fgets() 從指標位置讀取一行 fgets($fp);
fread() 從指標位置讀取指定長度 fread($fp, $length);
fwrite() 從指標位置寫入 fwrite($fp, $string);
fclose() 關閉檔案 fclose($fp);

檔案指標(File Pointer)其實就跟你打字時會閃爍的游標很像,在開啟檔案時它會在開頭的位置,讀取和寫入後,都會移動到讀取/寫入文字的後方

要解決剛剛那個問題很簡單,只要在讀取時就把檔案鎖住(LOCK_EX),寫入完畢時釋放(LOCK_UN)就行了

// 開啟檔案
$fp = fopen('data.txt', 'r+');
// 上鎖
if (flock($fp, LOCK_EX)) {
    // 讀取整份檔案,並存進 data 變數
    $data = fread($fp, filesize('data.txt'));
    // 修改 data 內容
    $data .= "增加一些內容\n";
    // 刪除檔案內容
    ftruncate($fp, 0);
    // 將指標歸零
    rewind($fp);
    // 寫入檔案
    fwrite($fp, $data);
    // 解鎖
    flock($fp, LOCK_UN);
    // 關閉檔案
    fclose($fp);
}

這樣的話就沒有人可以在你讀寫時存取檔案,必須等到你解鎖他才能讀取

fopen 模式:

符號 模式 說明
r 讀取 不存在會出錯,指標在開頭
r+ 讀取、寫入 r
w 寫入 不存在會建立檔案,指標在開頭,清空檔案
w+ 讀取、寫入 w
a 寫入 不存在會建立檔案,指標在結尾。fseek()無效,寫入總是在結尾。
a+ 讀取、寫入 a
x 寫入 已存在會出錯,指標在開頭
x+ 讀取、寫入 x
c 寫入 不存在會建立檔案,指標在開頭,不清空檔案
c+ 讀取、寫入 c

flock 選項:

選項 說明
LOCK_SH 可以讀取,不能寫入(其他人)
LOCK_EX 不能讀取和寫入(其他人)
LOCK_UN 釋放 LOCK
LOCK_NB 嘗試非阻塞

所有檔案處理函式:https://www.php.net/manual/en/ref.filesystem.php


cURL

cURL 是一個用於網路傳輸的開源工具(函式庫),在 Windows 10 的小黑框中也能使用

函式 說明 用法
curl_init() 初始化連線 curl_init($url)
curl_setopt() 設定傳輸選項 curl_setopt($ch, $option, $value)
curl_setopt_array() 以陣列方式設定傳輸選項 curl_array($ch, $options)
curl_exec() 執行傳輸 curl_exec($ch)
curl_getinfo() 讀取回應資訊 curl_getinfo($ch, $option)
curl_close() 關閉連線 curl_close($ch)

所有 cURL 函式:https://www.php.net/manual/en/ref.curl.php

其實主要就這四個步驟:

  1. 初始化連線
  2. 設定傳輸選項
  3. 執行傳輸
  4. 關閉連線

很容易對吧~

curl_setopt 選項:

選項 說明
CURLOPT_RETURNTRANSFER 返回字串而不是直接輸出
CURLOPT_CONNECTTIMEOUT 嘗試連線的最大秒數
CURLOPT_TIMEOUT 設定函式執行的最長秒數
CURLOPT_POST 發送 POST 請求
CURLOPT_POSTFIELDS 設定傳送的檔案
CURLOPT_HTTPHEADER 設定 HTTP 檔頭(Header)

所有 cURL 選項:https://www.php.net/manual/en/function.curl-setopt.php

// HTTP GET
$handle = curl_init("https://httpbin.org/get?a=air&b=bag&c=cat");
curl_setopt($handle, CURLOPT_RETURNTRANSFER, true);
curl_setopt($handle, CURLOPT_CONNECTTIMEOUT, 5);
curl_setopt($handle, CURLOPT_TIMEOUT, 60);
$response = curl_exec($handle);
curl_close($handle);
echo $response;

// HTTP POST
$handle = curl_init("https://httpbin.org/post");
curl_setopt_array($handle, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CONNECTTIMEOUT => 5,
    CURLOPT_TIMEOUT => 60,
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => json_encode([
        'a' => 'air',
        'b' => 'bag',
        'c' => 'cat'
    ]),
    CURLOPT_HTTPHEADER => [
        "Content-Type: application/json"
    ]
]);
$response = curl_exec($handle);
curl_close($handle);
echo $response;

上一篇
【PHP Telegram Bot】Day15 - 基礎(4):陣列處理、JSON
下一篇
【PHP Telegram Bot】Day17 - 基礎(6):函式與作用域
系列文
用 PHP 打造專屬於自己的 Telegram 聊天機器人吧!30

尚未有邦友留言

立即登入留言