【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;

<<:  Day09【Web】跨来源资源共用 CORS

>>:  Day 10 - Subscribe 订阅盘中报价资讯(Stocks)

资安学习路上-Linux基础与Web基础1

决定好学习方向後(台科大资安研究社社课为主),发现他的课程有连续性,直接一口气买了110年上下两个学...

Day 04: 进入主题前的补充:SOLID

为什麽要补充? 当决定铁人赛的题目是 Design Patterns 时,除了先 Google 看看...

Day 23 AWS的云上排队服务-SQS

想知道如何在云端上传递和处理来自使用者的网路请求讯息吗?AWS的SQS可以帮助我们做到这一点。我们往...

Orthogonal 3D 投影

大家好,我是西瓜,你现在看到的是 2021 iThome 铁人赛『如何在网页中绘制 3D 场景?从 ...

鼠年全马铁人挑战 WEEK 37:封包测试工具 - Charles (二)

           Photo on charlesproxy.com 前言 上个礼拜简单的分享...