绝大多数文档历史久远,可能具有10年以上的历史,此篇亦然. 请酌情参考. ⚠️
- MVC: Model View Controller
- php-fpm: 实现了
fastcgi
协议,底层还是调用了php-cgi
,但是有一个进程池.修改php.ini
后可以平稳过度.
Common Packages
https://github.com/ziadoz/awesome-php
https://getgrav.org/ https://github.com/getgrav/grav 不依赖db的markdownCMS
https://lumen.laravel.com/
https://laravel.com/ http://www.golaravel.com/
https://github.com/johnlui/Learn-Laravel-5
https://github.com/serbanghita/Mobile-Detect
https://github.com/overtrue/wechat
mail: https://github.com/PHPMailer/PHPMailer
pay: https://pay.weixin.qq.com/wiki/doc/api/external/jsapi.php?chapter=11_1
requests: https://github.com/rmccue/Requests https://github.com/guzzle/guzzle
markdown: https://github.com/erusev/parsedown
errorhandle: https://github.com/filp/whoops
Install
dnf module list php # 1.18默认还是没有stream模块!
dnf module enable php:remi-8.0 -y
dnf install -y php php-mysqlnd php-gd
chown -R nginx:nginx wp
systemctl daemon-reload
systemctl restart php-fpm # reload...
systemctl enable php-fmp
php-cgi.exe -b localhost:9000 -c php.ini
start nginx.exe
php.ini
error_reporting = E_ALL &~ E_DEPRECATED
display_errors = Off
log_errors = On
error_log = /home/php_errors.log
date.timezone = Asia/Shanghai
post_max_size = 128M
upload_max_filesize = 1024M
# 这几个一般默认无需指定
memory_limit = 512M
short_open_tag = On
# 相当于php语言级别的一个优化,避免重复编译,语言及缓存.该扩展7版本自带,但没有enable!
opcache.enable=1
opcache.enable_cli=1
opcache.memory_consumption=128
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=1000
# extensions
extension=memcached
extension=imagick.so
Source Install
https://www.php.net/downloads.php
https://www.cnblogs.com/alliancehacker/p/12255445.html
注意: libdir指定输出库文件目录; with-libdir指定查找依赖库文件目录,默认是lib!
注意: 与nginx类似,不指定prefix时,配置文件会放在/usr/local/etc
查看之前的php编译信息: php -i|grep configure
选项变更:
https://www.php.net/manual/en/migration74.other-changes.php
选项记录: /usr/local/php/bin/php-config
php7.4不支持的选项: --with-mysql --with-mcrypt --enable-gd-native-ttf --with-png[-dir] --with-libxml-dir --with-libmemcached(需要事后安装)
php7.4需要修改的选项: --with-freetype --with-jpeg --with-zip --enable-gd # 无-dir后缀! 旧:--enable-zip --with-gd
yum install -y sqlite-devel oniguruma libcurl-devel freetype-devel libmemcached-devel memcached ImageMagick
yum install -y bzip2-devel libjpeg-devel libpng-devel gmp-devel libmcrypt-devel mhash-devel readline-devel libxml2-devel libxslt-devel gd
oniguruma-devel: https://pkgs.org/download/oniguruma-devel
rpm -ivh http://mirror.centos.org/centos/8/PowerTools/x86_64/os/Packages/oniguruma-devel-6.8.2-1.el8.x86_64.rpm
php* pear* pecl phar* # 卸载
# libzip
# 如果出现宏(LIBZIP_VERSION_MICRO)错误,则应去掉其定义中的字母:
# libzip/zipconf.h /usr/local/include/zipconf.h
yum install cmake3; ln -fs ...
wget https://libzip.org/download/libzip-1.5.2.tar.xz
cmake . && make VERBOSE=1 # -DENABLE_OPENSSL=OFF
make install && ldconfig
# iconv
wget https://ftp.gnu.org/pub/gnu/libiconv/libiconv-1.16.tar.gz
./configure --prefix=/usr/local/libiconv --enable-static --libdir=/usr/local/lib64
# libssh
wget https://www.libssh2.org/download/libssh2-1.8.2.tar.gz
./configure --libdir=/usr/local/lib64
# libre2c
https://github.com/skvadrik/re2c/releases http://re2c.org/install/install.html
./configure --libdir=/usr/local/lib64
# openldap
# --prefix=/usr/local/openldap: 不全部安装在该目录也可以,否则依赖它的其他库很难找到头+库文件.配置文件放在/usr/local/etc
wget ftp://ftp.openldap.org/pub/OpenLDAP/openldap-release/openldap-2.4.47.tgz
./configure --libdir=/usr/local/lib64 --disable-bdb --disable-hdb
make depend && make && make install && ldconfig
configure
Option | Function |
---|---|
disable-fileinfo | 如果内存<1GB,编译可能会失败 |
exif | 图片元数据支持 |
calendar | 打开日历扩展功能 |
readline | readline_xxx等命令行函数 |
gmp | gmp_xxx相关数值计算函数 |
pear | 与composer一样的作用 |
phar | 将多个php文件打包成一个文件,如composer.phar |
libxml-dir | 打开libxml2库的支持 |
mcmath | 打开图片大小调整 |
xsl | 打开xslt文件,libxslt依赖于xml2 |
shmop+sysvsem | 支持IPC相关函数 |
inline-optimization | 优化线程 |
gd-native-ttf | TrueType字符串函数 |
disable-rpath | 关闭额外的运行库文件 |
./configure --prefix=/usr/local/php --with-config-file-path=/usr/local/php/etc --with-config-file-scan-dir=/usr/local/php/conf.d --with-libdir=lib64 --libdir=/usr/local/lib64
--enable-fpm --with-fpm-user=www --with-fpm-group=www --with-mysqli=mysqlnd --with-pdo-mysql=mysqlnd --enable-pdo
--with-freetype=/usr/local/freetype --with-jpeg --with-zlib --with-bz2 --with-mhash --with-curl=/usr/local/curl
--with-openssl=/usr/local/openssl --with-gettext --with-iconv --with-zip --with-xsl --with-xmlrpc --with-libxml --enable-xml
--enable-gd --enable-bcmath --enable-shmop --enable-sysvsem --enable-inline-optimization --enable-mbregex --enable-mbstring
--enable-ftp --enable-pcntl --enable-sockets --enable-soap --enable-opcache --enable-intl --enable-exif --enable-calendar
--disable-rpath --disable-fileinfo --disable-debug
make
make ZEND_EXTRA_LIBS='-liconv' && make install # 内存不足时禁用-j4; 否则会提示不能链接到iconv,或手动编辑Makefile修改extra_lib
cp php.ini-development /usr/local/etc/php.ini # date.timezone=Asia/Shanghai mysqli
# cp [sapi/fpm/]php-fpm.service /etc/systemd/system # 居然不奏效,必须使用init.d的!!
cp sapi/fpm/init.d.php-fpm /etc/init.d/php-fpm; chmod +x /etc/init.d/php-fpm;
cp php-fpm.conf /usr/local/etc # 也可能在etc目录已经有了; 最后一行: include=/usr/local/etc/php-fpm.d/*.conf
cp www.conf /usr/local/etc/php-fpm.d # 也可能在etc目录已经有了; user=www group=www 与nginx.conf中的user一致
ln -s /usr/local/php/sbin/* /usr/local/sbin
ln -s /usr/local/php/bin/* /usr/local/bin
disable-fileinfo 后内存还是不足
# 获取要增加的2G的SWAP文件块
dd if=/dev/zero of=/swapfile bs=1k count=2048000
# 创建SWAP文件
mkswap /swapfile
# 激活SWAP文件
swapon /swapfile
# 查看SWAP信息是否正确
swapon -s
# 添加到fstab文件中让系统引导时自动启动
echo "/var/swapfile swap swap defaults 0 0" >> /etc/fstab
# 不想要了可以删除交换分区
swapoff /swapfile
rm -rf /swapfile
# 启用策略,物理内存剩下40%的时候启用虚拟内存!
vim /etc/sysctl.conf
#vm.swappiness = 60
memcached install
https://cyhour.com/669/ https://github.com/tollmanz/wordpress-pecl-memcached-object-cache https://launchpad.net/libmemcached/+download https://github.com/php-memcached-dev/php-memcached
cd memcached-3.1.4; phpize;
./configure --with-php-config=/usr/local/php/bin/php-config --with-libmemcached-dir=/usr/local/libmemcached
make; make install;
vim /usr/local/php/etc/php.ini; extension=memcached
cp object-cache.php wp-content
# WordPress若没有成功连接到memcached, 这时候可以在 wp-config.php 加入如下参数
global $memcached_servers;
$memcached_servers = array(
array(
'127.0.0.1', // Memcached服务器IP
11211
)
);
composer & phpMyAdmin
# install composer
mv composer.phar /usr/local/bin/composer
wget http://pear.php.net/go-pear.phar && /usr/local/php/bin/php go-pear.phar
curl -sS https://getcomposer.org/installer | php # 注意改下第5个item:lib64
# 权限不要给太多,755就够了,多了还会报错
# 主页如果有其他其实警告请根据提示,在页面创建phpmyadmin数据库
wget https://files.phpmyadmin.net/phpMyAdmin/4.8.5/phpMyAdmin-4.8.5-all-languages.tar.xz
mv phpMyAdmin-4.8.5-all-languages /srv/www/phpadmin485
cp config.sample.inc.php config.inc.php
vim config.inc.php # localhost改成172.0.0.1 其他不用动,若auth_type是config的话则下方要配置用户名和密码
mkdir tmp # 在phpmyadmin目录下建立并给与www用户的写权限.
basic
除了变量,关键字都是不区分大小写的
基本数据类型有
bool int float string # 标量类型,关键字不区分大小写
array object resource null # null: 未被赋值,unset销毁的,没有返回值的函数输出
*= /= %= .= ++x x-- ?= === !== <=> # <=>:php7二元比较运算符,返回-1,0,1
<meta charset="utf-8"> // 或者类似下面的header方式知名编码
<?php
header('content-type:text/html; charset=utf-8');
set_include_path('d:' . get_include_path());
include 'a.php'; // 遇到错误继续执行,但如果被包含的文件中含有exit/die;则仍然会整个种终止.
require 'b.php'; // 遇到错误停止执行,当然也可以用变量接收其返回(php代码中return的内容).
include_onece 'c.php' // 有些逻辑只能加载一次,如包含数据库的连接逻辑
require_onece 'd.php'
declare(encoding='UTF-8');
namespace {
/*
* false: 0 0.0 '0' '' [] null undefined
* true: (bool)'0.0' (bool)'00' (bool)'false' (bool)'null'
*/
if (!defined('PI')) {
define('PI', 3.14, true); // 不区分大小写的const.注意:常量无作用域的概念!使用时无需$.
}
const E = 2.71828; // E可在表达式中直接引用或者:
$var = constant("E") + "1ab" // 3.71828, php的加法只能用于整数!字符串连接用点或双引号中直接解析$var,或写为${var}或{$var}.
$num = 0b1001; // 0:八进制 0x:十六进制
$num = bindec($num); // 进制转换 decoct hexdec dechex
$num = "a1" + true; // 1, 注意:+、++、-、--、==只能作用于数字类型.故字符串等会转换为数字,转换失败则为0.
$str = (string)$num; // == setType($num, string)
assert("$str == $num"); // 注意:3个等号才是类型也相等.此处会先把$str转换为数字类型!注意:双引号中的才会转义$var
$str = "leiz${num}\a"; // 字符串尽量使用双引号,因为单引号不会转义!
$arr = array('a', 2=>'b', 'c', 5=>'d', 'A'='e', f, // 0:'a' 3:4 6:f
"one" => [1, "hello",] // 5.4以上可以支持这种简写
);
$$a; // 先取$a的值,再取该值为名的变量的值.即可递归. 注意:也可以把函数名保存在变量中!
echo "...{$num}..." // 可直接在浏览器中打开php文件,查看结果.此处是取变量的值,类似于bash.
echo <<<str // 字符串定界符,下面的$var会被解析,若不想解析则使用'str'!
....$var
str;
}
function
// 进入B空间需要再声明下到B.B空间可以访问到C中的成员但是要加前缀B\C\func1或\A\B\C\func1!
// 命名空间与cpp不同,它只管辖: 常量、函数、类!各种变量还是上下贯通的!
namespace A\B\C;
use \D\E\F\{func2,func1}; // php7语法,否则需要分开写成两行
list($a, $b) = $arr; // $a="one", $b="two"; 注意:只能是索引数组!
while (list($key, $val) = each($arr)) {
do {
} while (...);
}
foreach ($arr as $key => &$val) {
/*
* 注意: 默认只遍历val!key无法引用传递,都是值传递!
* 注意: 可遍历数组或对象属性,赋值完且指针后移后,才进入循环体!
*/
}
for ($i=0; $i<count($arr); ++$i) {
for ($j=0; $j<count($arr[$i]; ++$j)) {
$arr[i][j];
}
}
// --------------- autoload
function __autoload($class_name) {
// 自动加载类:当前页面被加载时,如果其中的代码有使用到的类找不到会在该处寻找$class_name.
// spl_autoload_register('Demo::autoload'):可以自定义其他自动加载类,默认的会自动失效
require $class_name.'.class.php';
require "./{$class_name}.class.php";
}
// --------------- lambda
$fn = function (&$args, $name='') use ($outvar) {
/*
* php函数一般会返回两种类型,第二种类型一般为bool,可以使用if(!res)来判断成功与否!
* 不指定任何参数,表变参! 参数可以有默认值但必须是字面值或常量. 实参多了也没事,会取前面足够的. 无需返回类型.
* &$args表引用传递, 但需注意:若此时实参是字面值或常量则报错! use表引用上头的外层变量(注意:不加&仍然是值传递!).
*/
$a = func_num_args(); // 变参函数获取参数个数
$arr = func_get_arsg(); // 返回一个array(),获取所有参数
try {
if (defiend("PI")) {
} else if () { // or elseif
$fn1 = create_function('$params1', 'funcbody1'); // $fn1居然可以延续到外面的作用域
} else () {
$fn1 = create_function('$params1', 'funcbody2');
}
switch () {
case label1: break;
default: {}
}
} catch (Exception e) {
}
static $num = 0; // 只能用在函数内部
global $global_var_name; // 声明使用这个外部的全局变量,用在函数内部!或者下面方式:
$GLOBALS['global_var_name']; // 也可以添加,后面任何作用域可以直接$..使用!
}
class
// final表该类后续不能被再继承.可以new一个动态类(变量存放类名)
// 接口使用interface声明, 需先继承类后实现接口
final class Demo extends Parent implement IHuman {
private const $name;
private static $instance; // 默认public
private function __construct($arg1, $arg2) { // $d=new Demo(1,2); __destruct
parent::__construct(); // 会自动调用
const consta = 0;
static $count = 1; // 比构造函数还快一步
$GLOBALS['anony'] = function () use ($count) { // 类似于 global count;
}
}
private function __clone() { // 当 $a = clone $b; 时调用
}
public static function getInstance() {
if (!self::$instance instanceof self) {
self::$instance = new self;
}
return self::$instance;
}
// 如果是override父类则参数也应该一致,但是构造函数除外!
public final function f1(Demo $name, $age) { // 也可不约束参数类型!
self::$count; // self指当前的类,注意访问静态成员也好加上$
$this->name = $name; // 注意:把this->name当做一个整体
}
public abstruct function f2();
function __tostring() { // 需转换为string时调用
}
function __invoke($para) { // 把对象当成函数调用时
}
function __get($attr) { // 访问private属性atrr
return $this->$attr; // $o->attr;
}
function __set($attr, $value) { // 给本类无法访问的属性atrr赋值时
$allow = array('name');
if (in_array($attr, $allow))
$this->$attr = $value; // 强制支持赋值: $o->attr1 = '1';
}
function __unset($attr) { // 销毁无法访问的属性时
unset(this->$attr);
}
function __isset($attr) { // 外部调用isset访问内部private属性attr时
return isset($this->$attr);
}
function __call($attr, $args) { // 外部调用一个不存在方法时,__callStatic:也必须加static修饰
$len = count($args);
if ($len < 1) {
}
}
}
common
M_PI
:系统定义的圆周率常数PHP_OS
:PHP运行的osPHP_EOL
:换行PHP_VERSION
:versionPHP_INT_MAX
:2147483647
. 注意:若再+1则类型变为float
!__FILE__
:当前网页文件的完整物理路径__LINE__
:当前网页文件所在的文件夹.与是否被include无关.__FUNCTON__
__METHOD__
__CLASS__
__NAMESPACE__
TRUE
FALSE
NULL
DIRECTORY_SEPARATOR
(/或) PATH_SEPARATOR
(:或;)$_GET
:$_GET['iname']
– <form method="get" action="1.php"><input name="iname" type="text"></form>
$_POST
:$_POST['age']
– <form method="post" action="1.php"><input name="age" type="text"></form>
$_REQUEST
:提交时即使用url中参数(action中指定),form又使用method=post方式.获取两者所有.$_SERVER['REQUEST_URI']
:请求的path路径,如 /wp-json/wp/v2/posts
$_SERVER['SERVER_ADDR']
:运行本脚本机器的ip$_SERVER['REMOTE_ADDR']
:浏览当前页面的用户的ip$_SERVER['QUERY_STRING']
:查询字符串$_SERVER['DOCUMENT_ROOT']
:==getcwd()
;项目index文件所在的根目录$_FILES
:[[’name’ => ‘’], [’type’ => ‘application/octet-stream’], [’error’ => 0], [‘size’ => 0], [’tmp_name’ => ‘服务器上保存的临时文件’]]
print_r($v); // 输出数组会比较好看写,不然就用echo,print.但是true/false仍然输出1和空.
var_dump($str); // string("leiz"),比较好的调试输出,可以准确输出变量的类型.数组的输出也比较美观. 一般会 var_dump(); die();
function_exists('funcname'); class_exists, method_exists, interface_exists..
empty($num); // false. 检测变量是否为空(参看上面的false的定义)
is_int($num); // true, is_object,is_array,is_integer,is_float|is_double|is_real,is_bool,is_string,is_resource,is_null
is_numeric($v); // int float string(数字字符串)
is_scalar($v); // int float bool string
is_callable($v); // 有效的函数名
getType($str); // "string"
get_parent_class($obj); // 若没有返回false,有则返回类名!
get_class_methods('Class'); //['method1', 'method2'],包括父类+public+static.类比get_class_vars(;)
// ---------------
$q = isset($_GET['q'])? htmlspecialchars($_GET['q']) : '';
$q = isset($_POST['q'])? $_POST['q'] : ''; // 多选/或复选框:<form..><select multiple name="q[]"><option value="oname">male</option></form> q["oname"]
isset($num); // 变量存在且!=null且可以被访问(private不行).
unset($arr); // 删除整个数组,下标会重新排序. 也可用来删除数组中的某个元素,此时下标会保留,故: $arr[]=1 会延续之前的索引
filter_var($var, FILTER_VALIDATE_INT, array("options"=>array("min_range"=>0, "max_range"=>256))); // true/false
int bccomp(string $l='', string $r='' [, int $scale=int]); // 任意精度比较,scale表示精确到小数点位数.0:l==r,1:l>r
$str = implode('-',$arr); // join数组中的元素
$arr = explode('-',$str); // 用-作为分隔符来分割到索引数组
// --------------- cookie
// $_COOKIE :服务端设置,下次客户端再带过来.val只能是string!key支持下标[]实际是字符串,只是php会帮助转换!
// $_SESSION:基于cookie,val类型丰富些(除了资源类型).数据存放在服务端,cookie则是存在客户端.
setcookie('key', 'val', time()+5, '/'); // 5s,默认是当前语句所在文件目录有效
setcookie('key', false); // delete key; '':也是删除; 不写第2个参数是清空val的值!
session_start(); // 同一页面开启两次会报提示性错误.可配置自动开启(php.ini):session.auto_start
session_id(); session_name();
$_SESSION['key'] = 'val';
array
$arr[] = '数组末尾追加'; // 如果数组不存在,将会被创建
$arr[3] == $arr['3'] != $arr['03']; // 等价与整数的字符串(不以0开头)会被当做整数来对待.如果是字母字符串则加不加引号无所谓,但推荐加上引号(否则不能常量区分)!
$arr["num$index"]; // 先进行变量替换
count($arr); // 如果是undefined则返回0,如果是对象则返回其属性的个数,如果是普通类型则返回1.
sort($arr); // 对value进行升序排列,返回索引数组.如果元素是又是个数组,则按其第1个元素排
arsort($arr); // 对value进行降序排列,保持原来的键值关联(key与value还是对应的,不像sort:key永远是0、1..的索引数组)
krsort($arr); // 对key进行降序排列,必然保持原来的键值关联
natsort($arr); // 自然排序,比如10不会排在1后面而是9后面
usort($arr,function($m,$n){})
shuffle($arr); // 打乱
next($arr); // prev() end($arr):使$arr的指针指向最后一个位置 reset():rewind 若next后$arr地址非法此时$arr1=$arr;会初始化为$arr的开始位置!
current($arr); // 当前位置的value(若指针非法则返回false). while ($val = current($arr)) { ... next($arr); }
key($arr); // 当前位置的key. 若要获得可以+value请使用each,见上面的while示例!
range(1,5); // [1,2,3,4,5],也可以降序:range('z','a');
in_array/array_search("value1", $arr, true); // true:区分数据类型(默认是false).注意:查找的是value!
array_key_exists('key',$var); // 检查关数据的key或索引数据的索引是否存在
array_values($arr); // 抽取出arr的value,转化为索引数组
array_keys($arr); // 返回一个索引数组
array_combine($keys,$values); // 把俩索引数组构成一个关联数组,若个数不一致则返回false!
array_key_exists($key); // 键名或索引是否存在
array_merge(arr1,arr2); // 针对关联数组,若key是整数则按照merge顺序重建0,1..索引.若key是string则按照merge顺序,重复的key被后面覆盖了!
array_rand(arr, 2); // 随机取2个元素,返回索引数组的下标
array_flip($arr); // 交换arr的key/value,value必须是string或int,最后一个为准
array_reverse($arr); // 不递归倒序元素(k/v作为一组).如果是索引数组,还可以指定额外参数为true来达到同k-v相同的效果(默认是只翻转索引对应的值)
array_count_values($arr); // arr中的value只能是string+int. array([value1]=>个数, ...);
array_unique($arr); // 首先将值作为字符串排序,然后对value相同的item,只保留第1个.
array_map('f1',$arr1,$arr2); // 对arr1中元素Xi及arr2中的元素Yi合起来作为做参数传递给f1(也可写成闭包),输出1个运算后的新数组.若f传入null则新数组元素是[Xi,Yi]
array_filter($arr, function($v){ return $v & 1; }); // 会检测arr中的每个value,返回true时保留到结果数组($arr不会被改变).不指定过滤函数时,则过滤掉值为false属性的元素.
array_push($arr,'rear插入');
array_pop($arr,'rear删除');
array_unshift($arr,'front插入');
array_shift($arr,'front删除');
string
int mb_strlen() // php_mbstring.dll
string substr($s,-2,2) // 从倒数第2个位置向后截取2个字符.若最后1个参数也是负数,则表示最后几个字符不截取
int strlen($str) // sprintf("",..) sscanf($str,"",...) strtolower() ucwords() trim()/triml/trimr
int strpos($str, "prefix", 0) // 若找到就返回其pos,否则返回false! stripos(); strripos();
int stristr($str, "substr") // strchr/strrchr返回的是匹配字符开头往后的字符串.
int strcasecmp($str, "substr")
array str_split($str, 2) // 两个字符一组分割到数组中,默认是1.如果参数<1则返回false.若参数过大则返回其本身构成的数组.
mixed str_replace($find, $replace, $str, $count) // $str可以是个array,查找所有find,替换为replace.count表替换的次数.返回替换后的结果.
string str_pad($s, 2, '0', STR_PAD_BOTH) // 0..0 默认是添加到最后,参数也可是个数值,会被转换为字符串!
string str_repeat($str, 2) // 把字符重复的次数
string md5(string) // e10adc.... 共32位字符
string nl2br(string) // \n to </br>
string htmlspecialchars(string) // html特殊符号转换为标准字符串
string strval(mixed $var) // 注意:大数应使用:sprintf("%0.0f",pow(2,50)),否则会转换成1...E+15格式! >5.2版本时,对象会调用__toString(). 类比intval,floatval.
--------------- url
string urlencode(string) // 将url中所有非字母数组的字符转换为%E7这种类似格式,空格编码为+号.
string http_build_query(mixed params) // 自动进行urlencode处理.也可以作用于类对象.会&拼接属性.array中也可以嵌套(附加特殊的后缀,如%5B)
array parse_url(string url) // 上面的逆
--------------- json
string json_encode($arr)
mixed json_decode($arr, true) // 默认是false:返回object,true:已array方式返回
date
// d :01-31 j:1-31 m:01-12 n:1-12 Y:2018 H:00-23 i:00-59 s:00-59 l:Sunday N:1-7 F:January M:Dec t:28-31 L:1(闰年) a/A:pm/AM T:EST(时区)
int gmmktime(16,18,22,4,17,2018);
int strtotime(string $format, int $timestamp=time()); // "-1 hours":表以当前时间为基准 "+1 week 2 days 2 seconds" "next Monday", 这样写也是合适的:"0 weeks"
string date(string $format, int $timestamp=time());
string date("Ymd", strtotime('-7 days', strtotime('20180328'))); // 指定日期的前7天的格式化
date_default_timezone_get(); // Asia/Shanghai. xxx_set
DateTime date_create("2018-04-17", timezone_open("Asia/Shanghai")); // 以下的$d均指DateTime类型
$d = date_create_from_format("j-M-Y", "15-Mar-2018");
int date_timestamp_get($d);
string date_format($d, "Y-m-d"); // 2018-04-17
DateInterval date_interval_create_from_date_string("40 days");
DateTime date_add($d, DateInterval); // date_sub(); 返回被修改的对象,失败时返回false.下同!
DateTime date_date_set($d, 2018,4,28);
DateTime date_time_set($d, 16, 5, 59);
DateTimeZone date_timezone_get($d);
int date_offset_get($d); // 3600. 时区偏移的秒数
DateInterval date_diff($d, $d1);
DateTime date_modify($d, "+15 days");
os / sys
// file
file_exists("");
$file = fopen("welcome.txt","r") or exit("Unable to open file!"); // 于当前目录打开一个文件,不行的话生成一段消息
while (!feof($file)) { // 逐行读取文件,直到文件末端为止
echo fgets($file). "<br />";
}
fclose($file);
// dir
mkdir('a/b/1.txt', 766, true); // true:递归
function getFile($path) {
$path = $_SERVER['DOCUMENT_ROOT']; // 根目录
$folder = opendir($path);
while ($f = readdir($folder)) {
if ($f == '.' || $f == '..') {
continue;
}
if (is_dir('{$path}/{$f}')) {
getFile('{$path}/{/$f}');
}
}
}
// ini and error
ini_set('log_errors', 'on'); // php.ini开日志
ini_set('error_reporting', E_ALL|E_STRICT); // 捕捉所有错误
ini_set('display_errors', 'off'); // 不显示到浏览器上
ini_set('error_log', 'd:/tmp/err.log'); // 日志输出目录
function customError($level, $errmsg, $file, $line) {
switch ($level) {
}
return false; // 再路由给php处理
}
set_error_handler('customError');
trigger_error('errmsg', E_USER_WARNING); // E_USER_ERROR..相当于throw
// file
is_file('1.txt');
file_exists('1.txt');
filesize('1.txt');
unlink('1.txt'); // del file
$fp = fopen('1.txt', 'r');
while (feof($fp)) {
fgets($fp); // 获取一行,fputs('不包括换行符');
}
fseek($fp, 0);
// serialize
$a = ['key1' => 'val1', 'key2' => 'val2'];
$s = serialize($a);
file_put_contents('c:/1.txt', $s);
require '1.class.php' // 如果序列化的是类,则需要引进来,否则反序列化时无法正确解释
$t = file_get_contents('c:/1.txt');
$by = unserialize($t);
pdo
$dsn = "mysql:host=..;port=3607;charset=utf8;dbname=test";
$pdo = new PDO($dsn, "root", "123");
$pdo->setAttribute(PDO::ATTR_CASE, PDO::CASE_LOWER); // 列名全部小写
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING); // db执行错误时输出错误信息.默认是silent的.
$sql = "insert admin values('$name', ip2long($_SERVER['REMOTE_ADDR']), time())"
int $pdo->exec($sql);
$pdo->lastInsertId();
$pdostmt = $pdo->query("select * from tb1");
$pdostmt->rowCount();
$pdostmt->columnCount();
$pdostmt->fetchColumn(1); // 获取第1行第2列的数据,然后又下移一行指针
$pdostmt->fetch(PDO::FETCH_OBJ); // 获取1整行数据,然后下移一行指针
$rows = array();
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$rows[] = $row
}
$rows = $stmt->fetchAll(); // [ [0 => ["id" => "1", ..]], ..]
foreach ($rows as $row) {
echo $row['id'];
}
// ---------------
$pdostml->prepare("insert into test values (:name, :age)");
$name = ''; $age = 0;
$arr = array(
':name' => $name,
':age' => $age
);
$ret = $pdostml->execute($arr);
if ($ret) {
echo 'ok';
}
// ---------------
$pdo->beginTransaction();
$ret = $pdo->exec('..');
if (!ret) {
$pdo->rollback();
}
...
$pdo->commit();
//
// mysql
//
$conn = @mysqli_connect('localhost','root','123456'); // resource. 默认端口3306,失败返回false.@用于屏蔽函数内部执行错误,防止给客户看到不该看的错误信息.
mysqli_select_db("db1", $conn); // bool
mysql_error();
mysql_query("set names utf8"); // resource: 设置返回数据的字符集. 失败时返回false,成功时返回结果集或true.
$res = mysql_query("select id, name from tb1", $conn);
$username = mysql_real_escape_string($username); // 字符串都用该函数转换下,可防止sql注入
mysql_fetch_array($res, MYSQL_ASSOC); // dict(key是列名)==mysql_fetch_assoc().
while ($row = mysql_fetch_row($res)) { // list==MYSQL_NUM, MYSQL_OBJ:对象,key是属性.
$row[0];
}
misc
//
// file upload
//
// enctype: 必须指定该项!否则文件上传不了!
// x-form-urlencoded: 传输少量的文本数据或二进制数据,默认值
// multipart/form-data: 字符串+文件
// text/plain: 大量文本数据
<form name="" enctype="application/form-data">
用户名: <input type="text" name="username" /><br/>
头像: <input type="file" name="image" /><br/>
<input type="submit" value="上传" />
</form>
if (isset($_POST['submit'])) {
$errno = $_FILES['image']['error'];
if ($errno) {
switch ($errno) {
case 1: echo '文件过大'; break;
case 2: echo '表单过大'; break;
case 3: echo '未上传完整'; break;
case 4: echo '未上传'; break;
case 6: echo '找不到临时文件'; break;
case 7: echo '写入失败'; break;
default: echo '未知错误';
}
}
// 多文件上传
foreach ($_FILES['image']['name'] as $index => $name) {
$finfo = finfo_open(FILEINFO_MIME);
$info = finfo_file($finfo, '1.txt');
$arr = explode(';', $info);
if (in_array($_FILES['image']['type'][$index], $arr)) {
// 判断文件类型,最准确的还是: php_fileinfo.dll
}
if ($_FILES['image']['size'][$index] > 1 * 1024 * 1024) {
die('');
}
if (!is_uploaded_file($_FILES['image']['tmp_name'][$index])) {
// 是http上传
}
$path = './uploads/' . uniqid() . strrchr(iconv('utf-8', 'gbk', $name));
if (move_uploaded_file($_FILES['file']['tmp_name'][$index], $path)) {
// uniqid('前缀', true:生成更长更唯一): 防止同名文件覆盖
// utf8 --> gbk
}
}
}