PHP各类功能实现(笔记)

------------------------------------------ 2017 -------------------------------------------

PHP file lock

一个完整的防文件冲突的读取过程应该是:

$file = 'test.txt';  
$fp = fopen($file, 'a');            // 打开文件
  
if(flock($fp, LOCK_EX)){            // 取得独占锁  
    fwrite($fp, "Hello World\r\n"); // 写入数据  
    flock($fp, LOCK_UN);            // 解锁  
}  
  
fclose($fp);                        // 关闭文件

PHP如何允许跨域访问

header('Access-Control-Allow-Origin: ' . $_SERVER['HTTP_ORIGIN']);
header('Access-Control-Allow-Credentials: true');

PHP文件上传验证

if (isset($_FILES['file']) && $_FILES['file']['error'] == UPLOAD_ERR_OK) {
    $file = $_FILES['file'];
    if ($file['error'] != UPLOAD_ERR_OK) {
        throw new Exception('file 上传错误');
    }
    if ($file['size'] > 8000 * 1024) {
        throw new Exception('file 附件不能大于8M');
    }

    // File type
    $finfo = new finfo(FILEINFO_MIME_TYPE);
    $type  = $finfo->file($file['tmp_name']);
    if ($type != 'image/jpeg' && $type != 'image/png' && $type != 'image/gif') {
        throw new Exception('MIME type only accept image jpeg/png/gif');
    }

    // Prepare save
    $filePath = APPLICATION_PATH . '/../data/files/';
    $fileExt  = pathinfo($file['name'], PATHINFO_EXTENSION);
    $fileName = $id . '.' . $fileExt;
    $i = 1;
    while (file_exists($filePath . $fileName)) {
        $fileName = $id . '.' . $i . '.' . $fileExt;
        $i++;
    }
    if (!move_uploaded_file($file['tmp_name'], $filePath . $fileName)) {
        throw new Exception('file 生成文件失败');
    }
}

PHP CURL 实例

$ch = curl_init('http://target.com/api/queue-msg');
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$res = curl_exec($ch);
curl_close($ch);

if (!$res) {
    sleep(mt_rand(3, 10)); // 3秒后再试一次
    $ch = curl_init('http://target.com/api/queue-msg');
    curl_setopt($ch, CURLOPT_TIMEOUT, 10);
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    $res = curl_exec($ch);
    curl_close($ch);
    if (!$res) {
        throw new Exception('InternalMsg: request failed or response is empty');
    }
}
if ($res != 'SUCCESS') {
    throw new Exception('InternalMsg: queue msg failed. response: ' . $res);
}

PHP开发之数据验证

  1. 环境准备: 让错误都显示出来
# install xdebug (出错提示更醒目,更清楚)
# php.ini
error_reporting = E_ALL | E_STRICT (php 5.3.10)
error_reporting = E_ALL (php 7.0.4)
display_errors = On
display_startup_errors = On
log_errors = On
track_errors = On
html_errors = On (apache2)
error_log = /var/log/php/apache2.log (apache2)
error_log = /var/log/php/cli.log (cli)
  1. 确保所需数据用户都提交了
// 错误示例1
$id = $_GET['id'];
$db->query("DELETE FROM table WHERE id = $id");
// 错误示例2
$db->insert('table', array(
    'to'        => $_POST['to'],
    'subject'   => $_POST['subject'],
    'body'      => $_POST['body'],
    'sender_id' => $_SESSION['uid']
));

不验证的后果:

  • Notice: Undefined index

  • SQL Error / SQL Injection

  • 无效的/无意义的/垃圾数据插入了数据库表
    验证方法:

// 例1
if (!isset($_GET['id'])) {
    throw new InvalidArgumentException('missing required key id');
}
// 例2
$requiredKeys = array('title', 'content');
foreach ($requiredKeys as $key) {
    if (!isset($_POST[$key])) {
        throw new InvalidArgumentException("missing required key $key");
    }
}
  1. GET/POST数据分析

$_GET/$_POST里的数据都是字符串(也会是数组,但数组里的数据最终还是字符串).
可分为四类: 指定范围内的字符串,有约定格式的字符串,数字,任意文本

  1. 指定范围内的字符串: 白名单验证
// 例1: 用户信息完善之性别验证 (已确保 gender 字段已提交)

// Bad
$db->update('user', array('gender' => $_POST['gender']), "uid = $uid");

// Good
if ($_POST['gender'] != 'male' && $_POST['gender'] != 'female') {
    throw new InvalidArgumentException('invalid gender');
}
$db->update('user', array('gender' => $_POST['gender']), "uid = $uid");

// 例2: 用户列表按状态显示 (已确保 status 字段已提交)

// Bad
$db->select()->from('user', '*')->where('status = ' . $_GET['status']);

// Good
class User {
    const STATUS_NEW        = 1;
    const STATUS_VERIFIED   = 2;
    const STATUS_EXPIRED    = 3;
    const STATUS_ARCHIVED   = 4;
}
$statusList = array(
    'all'                   => true,
    User::STATUS_NEW        => true,
    User::STATUS_VERIFIED   => true,
    User::STATUS_EXPIRED    => true,
    User::STATUS_ARCHIVED   => true
);
$status = $_GET['status'];
if (!$status || !isset($statusList[$status])) {
    $status = 'all';
}
$select = $db->select()->from('user', '*');
if ($status != 'all') {
    $select->where("status = $status");
}

// Why Not in_array() ???
var_dump(in_array('1 any chars', $statusList)) === true // SQL injection here !!!
  1. 有约定格式的字符串: 长度 + 正则
// 例1: email
$email = filter_var($_POST['email'], FILTER_VALIDATE_EMAIL);
if (!$email) {
    throew new InvalidArgumentException('invalid email');
}

// 例2: id list (3,4,5,6,7)
$ids = $_GET['ids'];
$len = strlen($ids);
if ($len == 0 || $len > 1000) {
    throw new InvalidArgumentException('ids required and maxlength is 1000');
}
if (!preg_match('/^\d+(,\d+)*$/', $ids)) {
    throw new InvalidArgumentException('invalid ids');
}
  1. 数字
// 例: 数据库表主键自增id
$id = filter_var($_GET['id'], FILTER_VALIDATE_INT, array('options' => array('min_range' => 1)));
if (!$id) {
    throw new InvalidArgumentException('invalid id');
}

// Why not is_numeric() ?
var_dump(is_numeric('1e360')) === true // SQL Error here !!!
  1. 任意文本: 长度
// 例: subject VARCHAR(500), body (TEXT)
$subject = trim($_POST['subject']);
$len     = mb_strlen($subject, 'UTF-8');
if ($len == 0 || $len > 500) {
    throw new InvalidArgumentException('subject required and maxlength is 500');
}

$body = trim($_POST['body']);
$len  = mb_strlen($body, 'UTF-8');
if ($len == 0 || $len > 65535) {
    throw new InvalidArgumentException('body required and maxlength is 65535');
}

// Why check length ?
If strict SQL mode is not enabled and you assign a value to a CHAR or VARCHAR column that exceeds the column's maximum length, the value is **truncated** to fit and a warning is generated.
发布了34 篇原创文章 · 获赞 4 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/Tianyi_liang/article/details/105638243