书籍:《PHP、MySQL与JavaScript学习手册》第四版

开始于第三章(๑•̀ㅂ•́)و✧

0x01 关于PHP

  • 标记符:以下两种均可以;但后者与XML不兼容,不提倡。

    1
    2
    3
    <?php
    echo "Hello world";
    ?>
    1
    2
    3
    <?
    echo "Hello world";
    ?>
  • 注释:多行注释不能嵌套。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    <?php
    //This is a comment
    echo "COMMENT";
    /*
    This
    is
    a
    comment */
    ?>
  • PHP是由C和Perl发展而来的,多类比C,有助于学习。

  • 变量名大小写敏感。

  • .运算符是连接

  • 逻辑运算符

    运算符 说明
    &&
    and 低优先级与
    ||
    or 低优先级或
    xor 异或
  • 自增自减运算和C语言相同。

  • 字符串:单引号是直接输出,也无法实现转义的功能。

    1
    2
    3
    4
    5
    <?php
    $j = 13;
    echo 'This is $j';
    echo "This is $j"; //双引号替换变量值
    ?>
  • 多行字符串输出或赋值

    1
    2
    3
    4
    5
    6
    7
    8
    9
    <?php
    $author = "Bill Gates";

    $text = "Measuring programming progress by lines of code is like
    Measuring aircraft building progress by weight.

    - $author.";

    ?>
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    <?php
    $author = "Brian W. Kernighan";
    //标签可以自己指定,但开始和结束相同,例如:_Start、Start等
    //开始标签后续不能添加其他信息
    echo <<<_END
    Debugging is twice as hard as writing the code in the first place.
    Therefore, if you write the code as cleverly as possible, you are,
    by definition, not smart enough to debug it.

    - $author.
    _END;
    //关闭的_END 标签必须单独一行
    ?>
  • 弱语言类型

    1
    2
    3
    4
    5
    6
    7
    8
    <?php
    $number = 1234*567;
    echo substr($number,3,1);
    echo "\n";
    $pi = "3.1415927";
    $radius = 5;
    echo $pi * ($radius * $radius);
    ?>

    结果:

    1
    2
    3
    lowbee 3 $php example3-11.php
    6
    78.5398175
  • 常量

    1
    2
    3
    <?php
    define("ROOT_LOCATION","/usr/local/www/");//define 定义
    $directory = ROOT_LOCATION; //使用常量不需要$
  • echo & print

    两者均是PHP的结构,不需要使用括号。

    echo:多个参数、不是函数,没有返回值,运行更快一些,不能作为复杂表达式的一部分

    print:一个参数、返回值是1,能作为复杂表达式的一部分

  • 变量作用域

    全局变量 静态变量 超级全局变量
    所有函数都可以使用的变量 函数内部多次使用的,变量值和调用次数有关的 预定义变量,包含程序的信息和环境等
    global $logged_in; function test(){
    static $count = 0;

    }
    $GLOBALS :全部的全局变量
    $_GET:GET方式获取的变量
    $_POST:POST方法获取的变量
    $_COOKIE:会话变量
  • htmlentities函数对用户传入的参数消毒==>将所有的字符转成html实体,例:< ==> &lt

0x02 PHP中的表达式和控制流

  • TRUE和FALSE是PHP中预定义的变量,可以用小写,而且小写更稳定,不允许被重新定义。

    1
    2
    3
    4
    5
    6
    <?php
    echo "a: [" . (20 > 9) . "]<br>";
    echo "b: [" . (5 == 6) . "]<br>";
    echo "c: [" . (1 == 0) . "]<br>";
    echo "d: [" . (1 == 1) . "]<br>";
    ?>

    结果如下:在PHP中FALSE被定义为NULL

    1
    2
    lowbee 4 $php example4-1.php 
    a: [1]<br>b: []<br>c: []<br>d: [1]<br>
  • 多重赋值语句

    1
    2
    3
    <?php
    $a = $b = $c =0;
    ?>
  • 一致性运算符 ===会阻止PHP进行自动的类型转换。

  • 条件语句

    • if…elseif…else

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      <?php
      if ($bank_balance < 100)
      {
      $money = 1000;
      $bank_balance += $money;
      }
      elseif ($bank_balance > 200)
      {
      $savings += 100;
      $bank_balance -= 100;
      }
      else
      {
      $savings += 50;
      $bank_balance -= 50;
      }
      ?>
    • switch…case

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      <?php
      switch ($page)
      {
      case "Home":
      echo "You selected Home";
      break;
      case "About":
      echo "You selected About";
      break;
      case "News":
      echo "You selected News";
      break;
      case "Login":
      echo "You selected Login";
      break;
      case "Links":
      echo "You selected Links";
      break;
      default:
      echo "Unrecognized selection";
      break;
      }
      ?>
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      <?php
      switch ($page):
      case "Home":
      echo "You selected Home";
      break;

      // etc...

      case "Links":
      echo "You selected Links";
      break;
      endswitch;
      ?>
    • 三目运算符:? :

      1
      2
      3
      <?php
      echo $fuel <= 1 ? "Fill tank now" : "There's enough fuel";
      ?>
  • 循环

    • while

    • do…while

    • for

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      <?php
      $fp = fopen("text.txt", 'wb');

      for ($j = 0 ; $j < 100 ; ++$j)
      {
      $written = fwrite($fp, "data");

      if ($written == FALSE) break;
      }

      fclose($fp);
      ?>
    • break跳出循环:也可以自己指定跳出多少层循环,如break 2;跳出两层循环。

    • continue:结束当前一次循环。

0x03 PHP函数与对象

  • phpinfo()

  • 三个字符串函数

    1
    2
    3
    4
    5
    <?php
    echo strrev(" .dlrow olleH"); // Reverse string
    echo str_repeat("Hip ", 2); // Repeat string
    echo strtoupper("hooray!"); // String to upper case
    ?>
  • 函数名大小写不敏感,但变量名敏感。

  • 函数被定义前调用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    <?php
    $a1 = "WILLIAM";
    $a2 = "henry";
    $a3 = "gatES";

    echo $a1 . " " . $a2 . " " . $a3 . "<br>";
    fix_names();
    echo $a1 . " " . $a2 . " " . $a3;

    function fix_names()
    {
    global $a1; $a1 = ucfirst(strtolower($a1));
    global $a2; $a2 = ucfirst(strtolower($a2));
    global $a3; $a3 = ucfirst(strtolower($a3));
    }
    ?>

    首先PHP不是单纯的按照行来边du解释边执行的,而是先由Zend引擎翻译PHP代码到zhiZend二进制操作码,然后dao再去执行操作码。对于function的位置,因为函数的作用域是全局的,所以只要定义了,那么就可以在任意位置去调用它。但是除了两种情况,函数必须在其调用之前定义,一是在条件语句中定义的函数,二是在函数中定义的函数。

    详见:https://www.php.net/manual/zh/functions.user-defined.php

  • PHP 5.4之后不再支持传参时传引用

  • 包含和请求文件

    函数 说明
    include 将文件试图导入,即便文件没有被找到,程序继续执行、不会报错。遇到一次,导入一次,会导致文件包含的嵌套问题,即:a包含b、c,b包含c。
    include_once 也是将文件试图导入。但导入前会检查文件是否被包含,若包含、跳过此命令。推荐使用。
    require 强制文件导入,导入失败程序会停止执行、并报错。遇到一次,请求包含一次。
    require_once 同include_once,会检查文件是否已经被包含。推荐使用。
  • 版本兼容问题:查看函数是否存在

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <?php
    if (function_exists("array_combine"))
    {
    echo "Function exists";
    }
    else
    {
    echo "Function does not exist - better write our own";
    }
    ?>
  • 类定义包括类名(大小写敏感)、属性及方法。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    <?php
    $object = new User;
    print_r($object); //_r代表按照常规阅读规格

    class User
    {
    public $name, $password;

    function save_user()
    {
    echo "Save User code goes here";
    }
    }
    ?>

    结果:命令行结果如下,浏览器输出会忽略所有空格。

    1
    2
    3
    4
    5
    User Object
    (
    [name] =>
    [password] =>
    )
  • 对象克隆

    • 以下是错误用例,$object1 与$object2均指向同一对象,并未实现对象复制。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    <?php
    $object1 = new User();
    $object1->name = "Alice";
    $object2 = $object1;
    $object2->name = "Amy";

    echo "object1 name = " . $object1->name . "<br>";
    echo "object2 name = " . $object2->name;

    class User
    {
    public $name;
    }
    ?>
    • 以下是正确姿势:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    <?php
    $object1 = new User();
    $object1->name = "Alice";
    $object2 = clone $object1; //====> 克隆对象
    $object2->name = "Amy";

    echo "object1 name = " . $object1->name . "<br>";
    echo "object2 name = " . $object2->name;

    class User
    {
    public $name;
    }
    ?>
  • 构造方法:方法1==>方法2

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <?php
    //方法1
    class User
    {
    function User($param1, $param2)
    {
    // Constructor statements go here
    }
    }
    ?>
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <?php
    //方法2
    class User
    {
    function __construct($param1, $param2)
    {
    // Constructor statements go here
    }
    }
    ?>
  • PHP5 析构方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    <?php
    class User
    {
    function __destruct()
    {
    // Destructor code goes here
    }
    }
    ?>
  • 类的静态方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    <?php
    User::pwd_string();

    class User
    {
    static function pwd_string()
    {
    echo "Please enter your password";
    }
    }
    ?>
  • 类中不必直接(显示)声明属性,但不提倡

    1
    2
    3
    4
    5
    6
    7
    8
    <?php
    $object1 = new User();
    $object1->name = "Alice";

    echo $object1->name;

    class User {}
    ?>
  • 声明常量

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    <?php
    Translate::lookup();

    class Translate
    {
    const ENGLISH = 0;
    const SPANISH = 1;
    const FRENCH = 2;
    const GERMAN = 3;
    // ...

    static function lookup()
    {
    echo self::SPANISH;
    }
    }
    ?>
  • 对象不能直接访问静态属性或常量

  • 继承

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    <?php
    $object = new Subscriber;
    $object->name = "Fred";
    $object->password = "pword";
    $object->phone = "012 345 6789";
    $object->email = "fred@bloggs.com";
    $object->display();

    class User
    {
    public $name, $password;

    function save_user()
    {
    echo "Save User code goes here";
    }
    }

    class Subscriber extends User //===>继承
    {
    public $phone, $email;

    function display()
    {
    echo "Name: " . $this->name . "<br>";
    echo "Pass: " . $this->password . "<br>";
    echo "Phone: " . $this->phone . "<br>";
    echo "Email: " . $this->email;
    }
    }
    ?>
    • parent运算符

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      <?php
      $object = new Son;
      $object->test();
      $object->test2();

      class Dad
      {
      function test()
      {
      echo "[Class Dad] I am your Father<br>";
      }
      }

      class Son extends Dad
      {
      function test()
      {
      echo "[Class Son] I am Luke<br>";
      }

      function test2()
      {
      parent::test();
      //若指明当前类的方法,可以使用 self::method(),即self::test()
      }
      }
      ?>
    • Final方法:防止子类方法覆盖父类方法

      1
      2
      3
      4
      5
      6
      7
      8
      <?php
      class User
      {
      final function hello()
      {
      echo "This is hello of son, not dad.";
      }
      }

0x04 PHP的数组

1.数值数组

不推荐方法1,难以维护数组,推荐使用方法2。

1
2
3
4
5
6
7
8
9
<?php
//方法1
$paper[] = "Copier";
$paper[] = "Inkjet";
$paper[] = "Laser";
$paper[] = "Photo";

print_r($paper);
?>
1
2
3
4
5
6
7
8
9
<?php
//方法2
$paper[0] = "Copier";
$paper[1] = "Inkjet";
$paper[2] = "Laser";
$paper[3] = "Photo";

print_r($paper);
?>

2.关联数组

通俗易懂,就是Python的字典。

1
2
3
4
5
6
7
8
9
10
11
12
<?php
$p1 = array("Copier", "Inkjet", "Laser", "Photo");

echo "p1 element: " . $p1[2] . "<br>";

$p2 = array('copier' => "Copier & Multipurpose",
'inkjet' => "Inkjet Printer",
'laser' => "Laser Printer",
'photo' => "Photographic Paper");

echo "p2 element: " . $p2['inkjet'] . "<br>";
?>
1
2
lowbee 6 $php example6-5.php 
p1 element: Laser<br>p2 element: Inkjet Printer<br>
  • 循环遍历数组:foreach…as

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <?php
    $paper = array("Copier", "Inkjet", "Laser", "Photo");
    $j = 0;

    foreach($paper as $item)
    {
    echo "$j: $item<br>";
    ++$j;
    }
    ?>
    1
    2
    3
    4
    5
    6
    7
    8
    9
    <?php
    $paper = array('copier' => "Copier & Multipurpose",
    'inkjet' => "Inkjet Printer",
    'laser' => "Laser Printer",
    'photo' => "Photographic Paper");

    foreach($paper as $item => $description)
    echo "$item: $description<br>";
    ?>
  • 循环遍历:list()和each()

    1
    2
    3
    4
    5
    6
    7
    8
    9
    <?php
    $paper = array('copier' => "Copier & Multipurpose",
    'inkjet' => "Inkjet Printer",
    'laser' => "Laser Printer",
    'photo' => "Photographic Paper");

    while (list($item, $description) = each($paper))
    echo "$item: $description<br>";
    ?>

3.多维数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<?php
$products = array(

'paper' => array(

'copier' => "Copier & Multipurpose",
'inkjet' => "Inkjet Printer",
'laser' => "Laser Printer",
'photo' => "Photographic Paper"),

'pens' => array(

'ball' => "Ball Point",
'hilite' => "Highlighters",
'marker' => "Markers"),

'misc' => array(

'tape' => "Sticky Tape",
'glue' => "Adhesives",
'clips' => "Paperclips"
)
);

echo "<pre>";

foreach($products as $section => $items)
foreach($items as $key => $value)
echo "$section:\t$key\t($value)<br>";

echo "</pre>";
?>

4.数组函数

  • is_array()

  • count():顶层元素数量

  • sort():排序,rsort() 反序排列

    • sort()直接在数组上排序

    • sort($a,SORT_NUMERIC) 按照数值排序

    • sort($a,SORT_STRING) 按照字符串排序

  • shuffle($cards) 对数组随机排序

  • explode():按照指定分隔符,切分字符串为数组

    1
    2
    3
    4
    <?php
    $temp = explode(' ', "This is a sentence with seven words");
    print_r($temp);
    ?>
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    Array
    (
    [0] => This
    [1] => is
    [2] => a
    [3] => sentence
    [4] => with
    [5] => seven
    [6] => words
    )
    1
    2
    3
    4
    <?php
    $temp = explode('***', "A***sentence***with***asterisks");
    print_r($temp);
    ?>
    1
    2
    3
    4
    5
    6
    7
    Array
    (
    [0] => A
    [1] => sentence
    [2] => with
    [3] => asterisks
    )
  • extract():将关联数组的键值对转成 变量=值 的形式

    常用于将$_GET与$_POST,用法:

    1
    2
    extract($_GET);//普通用法
    extract($_GET,EXTR_PREFIX_ALL,'fromget');//变量名都有前缀fromget,防止变量名的重复而覆盖
  • compact():作用与 extract()相反

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    <?php
    $fname = "Doctor";
    $sname = "Who";
    $planet = "Gallifrey";
    $system = "Gridlock";
    $constellation = "Kasterborous";

    $contact = compact('fname', 'sname', 'planet', 'system', 'constellation');

    print_r($contact);
    ?>
    1
    2
    3
    4
    5
    6
    7
    8
    Array
    (
    [fname] => Doctor
    [sname] => Who
    [planet] => Gallifrey
    [system] => Gridlock
    [constellation] => Kasterborous
    )
  • reset():循环遍历过程中,将指向下一个元素的指针指向数组开始。

    1
    2
    reset($a);//丢弃返回值
    $item = reset($a);//在$item中保存数组中第一个元素
  • end()

    1
    2
    end($a);//将数组指针移动到最后
    $item = end($a);//在$item中保存数组最后的元素

0x05 实用PHP技术

1.打印格式

printf()printecho的强大之处在于,格式化输出格式,常见的数字转换、控制精度、填充字符等;和C语言中的 printf()极为相似。sprintf()可以将打印结果存在变量中,不用输出至浏览器。

2.时间格式

​ 使用UNIX的时间戳,按秒数存储。

1
2
3
4
5
6
7
echo time(); //当前时间戳
echo time()+7*24*60*60; //下周此时的时间戳
echo mktime(0,0,0,1,1,2000); //2000年一月一日第一秒的时间戳
//从左至右参数
//时、分、秒、月、日、年(1970~2038)

date($format,$timestamp);//转变时间戳的输出格式

由于时间戳只能到2038年,因此会出现Y2K38漏洞,在PHP5.2 引入DateTime类解决问题,仅在64位计算机。

1
2
3
4
5
6
7
8
<?php
$month = 9; // September (only has 30 days)
$day = 31; // 31st
$year = 2018; // 2018

if (checkdate($month, $day, $year)) echo "Date is valid";//检查日期是否合法
else echo "Date is invalid";
?>

3.文件操作

​ Windows和MacOS X对文件命名大小是不敏感的,Linux和Unix是敏感的。区分大小写是好习惯。

  • 文件写
1
2
3
4
5
6
7
8
9
10
11
12
13
<?php //文件写操作 
if(file_exists("testfile.txt")) echo "File exists.";//检查文件是会否存在函数
$fh = fopen("testfile.txt", 'w') or die("Failed to create file");
$text = <<<_END
Line 1
Line 2
Line 3
_END;

fwrite($fh, $text) or die("Could not write to file");
fclose($fh);
echo "File 'testfile.txt' written successfully";
?>
  • 文件读
1
2
3
4
5
6
7
8
9
10
<?php //文件读操作
$fh = fopen("testfile.txt", 'r') or
die("File does not exist or you lack permission to open it");

$line = fgets($fh);
$text = fread($fh,3); //常用于读取二进制文件,注意换行符个数
fclose($fh);
echo $line;//Line 1
echo $text;//Lin
?>
  • 复制、移动、删除
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php //使用前最好用file_exists()检查文件是否存在
//复制
if (!copy('testfile.txt', 'testfile2.txt'))
echo "Could not copy file";
else echo "File successfully copied to 'testfile2.txt'";
//移动
if (!rename('testfile2.txt', 'testfile2.new'))
echo "Could not rename file";
else
echo "File successfully renamed to 'testfile2.new'";
//删除
if (!unlink('testfile2.new'))
echo "Could not delete file";
else
echo "File 'testfile2.new' successfully deleted";
?>
  • 文件更新
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php //更新文件
$fh = fopen("testfile.txt", 'r+') or die("Failed to open file");
$text = fgets($fh);

if (flock($fh, LOCK_EX)) //文件加锁
{
fseek($fh, 0, SEEK_END);
fwrite($fh, "$text") or die("Could not write to file");
flock($fh, LOCK_UN); //文件解锁
}

fclose($fh);
echo "File 'testfile.txt' successfully updated";
?>

说明:不是所有的文件系统都支持文件加锁。

fseek()参数说明:

  • 第一参数$fh:指处理的文件
  • 第二参数:文件内部指针偏移量,记为n。
  • 第三参数:
    • SEEK_END:从文件末尾往前偏移n位
    • SEEK_SET:指向n的位置
    • SEEK_CUR:在当前基础上往后偏移n位
  • 简易读取
1
2
echo file_get_contents("testfile.txt"); //简单明了的读取文件全部内容
echo file_get_contents("http://lowbee.fun");//也可获取在线文件
  • 文件上传
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<?php 
echo <<<_END
<html><head><title>PHP Form Upload</title></head><body>
<form method='post' action='upload2.php' enctype='multipart/form-data'>
Select a JPG, GIF, PNG or TIF File:
<input type='file' name='filename' size='10'>
<input type='submit' value='Upload'></form>
_END;

if ($_FILES)
{
$name = $_FILES['filename']['name'];
switch($_FILES['filename']['type'])
{
case 'image/jpeg': $ext = 'jpg'; break;
case 'image/gif': $ext = 'gif'; break;
case 'image/png': $ext = 'png'; break;
case 'image/tiff': $ext = 'tif'; break;
default: $ext = ''; break;
}
if ($ext)
{
$n = "image.$ext";
move_uploaded_file($_FILES['filename']['tmp_name'], $n);//将临时存储文件转为永久存储文件
echo "Uploaded image '$name' as '$n':<br>";
echo "<img src='$n'>";
}
else echo "'$name' is not an accepted image file";
}
else echo "No image has been uploaded";

echo "</body></html>";
?>

假设提交表单时文件名为 file,前端定义的文件名:

数组元素 内容
$_FILES[‘file’][‘name’] 上传文件名
$_FILES[‘file’][‘type’] 文件类型(如image/jpeg)
$_FILES[‘file’][‘size’] 文件大小(字节)
$_FILES[‘file’][‘tmp_name’] 临时服务器上的文件名
$_FILES[‘file’][‘error’] 错误代码

4.系统调用

exec()函数的使用。

1
2
3
4
5
6
7
8
9
<?php
$cmd = "pwd";
exec(escapeshellcmd($cmd),$output,$status);
if($status) echo "Error";
else
{
foreach($output as $line) echo $line."\n";
}
?>
  • $status保存运行状态

  • $output保存返回结果

  • escapeshellcmd():转义存在欺骗的字符

    反斜线(\)会在以下字符之前插入: *&#;`|*?~<>^()[]{}$*, \x0A\xFF" 仅在不配对儿的时候被转义。 在 Windows 平台上,所有这些字符以及 %! 字符都会被空格代替。