面向对象进阶之:Interface

/**
 *  使用Interface 实现收集不同源的文本数据.
 */

/**
 * Interface Documentable
 */
Interface Documentable {
  public function getID();
  public function getContent();
}

class DocumentStore {
  protected $data = [];

  public function addDocument(Documentable $document) {
    $key = $document->getId();
    $value = $document->getContent();
    $this->data[$key] = $value;
  }

  public function getDocument() {
    return $this->data;
  }
}

class HtmlDocument implements Documentable{

  protected $url;

  public function __construct($url) {
    $this->url = $url;
  }

  public function getID() {
    return $this->url;
  }

  public function getContent() {
    return file_get_contents($this->url);
  }
}

class StreamDocument implements Documentable {

  protected $resource;
  protected $buffer;

  public function __construct($resource, $buffer = 4096) {
    $this->resource = $resource;
    $this->buffer = $buffer;
  }

  public function getID() {
    return 'resouce-' . (int)$this->resource;
  }

  public function getContent() {
    $streamContent = '';
    rewind($this->resource);
    while (feof($this->resource) === false) {
      $streamContent .= fread($this->resource, $this->buffer);
    }
    return $streamContent;
  }
}

class CommandOuputDocument implements Documentable {

  protected $command;

  public function __construct($command) {
    $this->command = $command;
  }

  public function getID() {
    return $this->command;
  }

  public function getContent() {
    return shell_exec($this->command);
  }
}


$documentStore = new DocumentStore();
$htmldoc = new HtmlDocument('https://www.php.net');
$documentStore->addDocument($htmldoc);

$streamdoc = new StreamDocument();
$documentStore->addDocument($streamdoc);

$commanddoc = new CommandOuputDocument('cat /etc/hosts');
$documentStore->addDocument($commanddoc);

var_dump($documentStore->getDocument());

PHP 面向对象的设计

有句话说,面向对象很难,设计出来可复用的面向对象更难.
我觉得我编程最弱的也就是面向对象,我觉得我没办法找出公有的元素. 我不知道什么属性该设置成Public什么设置成Private. 什么样的函数该写什么样的东西. 我准备好好强化一下这方面的能力. 我买了设计模式这本书, 然后发现这样的书根本不适合我。 不如直接去看别人写的代码.
于是我找到了第一个可以参考的上传类:
https://github.com/aivis/PHP-file-upload-class/blob/master/upload.php

我也自己构建了一个基本的上传类

class Upload {

  protected $max = '2MB';
  protected $upload_path;
  protected $errors = [];
  protected $file;
  protected $newname;
  protected $ext = [];

  public function __construct($file, $upload_path) {
    $this->setFile($file);
    $this->setUploadPath($upload_path);
  }

  protected function setFile() {}
  public function setUploadPath() {}
  public function setMax() {}
  public function setAllowMineType() {}
  public function setNewName() {}
  public function setAllowExt() {}

  public function save() {}

  public static function Factory($file, $upload_dir) {
    return new static($file, $upload_dir);
  }

}

因为之前一直使用Laravel, 所以对Laravel Collection也非常喜欢,代码很优雅,如何处理链式的数组
https://github.com/illuminate/support/blob/master/Collection.php

Curl 上传图片

Bash

curl -F --from=@/Users/zhouitpro/Downloads/xj.jpg http://www.baidu.com

PHP curl 上传图片

$ch = curl_init();
$data = array('name' => 'Foo', 'file' => '@/path/to/image.jpeg');
curl_setopt($ch, CURLOPT_URL, 'http://localhost/upload.php');
curl_setopt($ch, CURLOPT_POST, 1);
//CURLOPT_SAFE_UPLOAD defaulted to true in 5.6.0
//So next line is required as of php >= 5.6.0
curl_setopt($ch, CURLOPT_SAFE_UPLOAD, false);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_exec($ch);

PHP 对比 Erlang

数组过滤

PHP 比较数组过滤

$arr = array(
  array(1, 9),
  array(1, 8),
  array(6, 10),
  array(15, 44),
  array(4, 6),
  array(30, 5),
);

$newarr = array();
foreach($arr as $key => $value) {
  if($value[0] > 10 && $value[1] > 10) {
    $newarr[] = $value;
  }
}

var_dump($newarr);

Erlang列表解析做相同的事

L = [{1,9},{1,8},{6,10},{15,44},{4,6},{30, 5}].
[{X,Y} || {X,Y} <- L, X >10, Y>10].

毕达哥拉斯三元组

$M = 11;
$R = array();

for($X = 1; $X < $M; $X++) {
  for($Y = 1; $Y < $M; $Y++) {
    for($Z = 1; $Z < $M; $Z++) {
      if($X > $Y && $Y > $Z && $Z*$Z + $Y * $Y == $X * $X) {
        $R[] = array($X, $Y, $Z);
      }
    }
  }
}
print '
';
print_r($R);

Erlang

pythag(N) -> [{A,B,C} || 
	A <- lists:seq(1, N),
        B <- lists:seq(1, N),
	C <- lists:seq(1, N),
	A < B,
	B < C,
	A*A + B*B =:= C*C
].

Centos 编译PHP-fpm mysql nginx

前言
我的编译目录分别为

/app/mysql
/app/php
/app/nginx

MYSQL

下载必要的软件

yum -y install make gcc-c++ cmake bison-devel  ncurses-devel

下载mysql, 这里现在最新的是5.6.26, 要下载其它的把URL后面的版本号改成你需要的版本号就可以了

wget http://cdn.mysql.com/Downloads/MySQL-5.6/mysql-5.6.26.tar.gz
tar -zxvf mysql-5.6.26.tar.gz
cd mysql-5.6.26

开始编译

cmake \
-DCMAKE_INSTALL_PREFIX=/app/mysql/ \
-DMYSQL_DATADIR=/app/mysql/data \
-DSYSCONFDIR=/etc \
-DWITH_MYISAM_STORAGE_ENGINE=1 \
-DWITH_INNOBASE_STORAGE_ENGINE=1 \
-DWITH_MEMORY_STORAGE_ENGINE=1 \
-DWITH_READLINE=1 \
-DMYSQL_UNIX_ADDR=/var/lib/mysql/mysql.sock \
-DMYSQL_TCP_PORT=3306 \
-DENABLED_LOCAL_INFILE=1 \
-DWITH_PARTITION_STORAGE_ENGINE=1 \
-DEXTRA_CHARSETS=all \
-DDEFAULT_CHARSET=utf8 \
-DDEFAULT_COLLATION=utf8_general_ci

make && make install

创建用户组

groupadd mysql
useradd -g mysql mysql

修改mysql目录权限

chown -R mysql:mysql /app/mysql

执行初始化配置

/app/mysql/scripts/mysql_install_db --basedir=/app/mysql --datadir=/app/mysql/data --user=mysql
#移除默认的my.cnf文件
mv /etc/my.cnf /etc/myback.cnf
cp /app/mysql/support-files/mysql.server /etc/init.d/mysql
chkconfig mysql on
#启动mysql
/etc/init.d/mysql start

编辑/etc/profile 增加

PATH=/app/mysql/bin:$PATH
export PATH
source /etc/profile

设置mysql密码

mysql_secure_installation

mysqlconfig

mysql基本配置

vim /app/mysql/my.cnf

[mysqld]
socket=/tmp/mysql.sock

建议sock文件

ln -s /tmp/mysql.sock /var/lib/mysql/mysql.sock

Nginx

安装必要软件

yum -y install gcc gcc-c++ make zlib-devel pcre-devel openssl-devel

下载nginx
http://nginx.org/en/download.html 选择最新的

wget http://nginx.org/download/nginx-1.9.5.tar.gz
tar -zxvf nginx-1.9.5.tar.gz
cd nginx-1.9.5

创建用户

useradd -r nginx

开始编译

./configure \
--user=nginx                          \
--group=nginx                         \
--prefix=/app/nginx                   \
--sbin-path=/usr/sbin/nginx           \
--conf-path=/app/nginx/nginx.conf     \
--pid-path=/var/run/nginx.pid         \
--lock-path=/var/run/nginx.lock       \
--error-log-path=/var/log/nginx/error.log \
--http-log-path=/var/log/nginx/access.log \
--with-http_gzip_static_module        \
--with-http_stub_status_module        \
--with-http_ssl_module                \
--with-pcre                           \
--with-file-aio                       \
--with-http_realip_module             \
--without-http_scgi_module            \
--without-http_uwsgi_module

make && make install

创建启动文件/etc/init.d/nginx

#!/bin/sh
#
# nginx - this script starts and stops the nginx daemin
#
# chkconfig:   - 85 15
# description:  Nginx is an HTTP(S) server, HTTP(S) reverse \
#               proxy and IMAP/POP3 proxy server
# processname: nginx
# config:      /etc/nginx/nginx.conf
# pidfile:     /var/run/nginx.pid
# user:        nginx

# Source function library.
. /etc/rc.d/init.d/functions

# Source networking configuration.
. /etc/sysconfig/network

# Check that networking is up.
[ "$NETWORKING" = "no" ] && exit 0

nginx="/usr/sbin/nginx"
prog=$(basename $nginx)

NGINX_CONF_FILE="/etc/nginx/nginx.conf"

lockfile=/var/run/nginx.lock

start() {
    [ -x $nginx ] || exit 5
    [ -f $NGINX_CONF_FILE ] || exit 6
    echo -n $"Starting $prog: "
    daemon $nginx -c $NGINX_CONF_FILE
    retval=$?
    echo
    [ $retval -eq 0 ] && touch $lockfile
    return $retval
}

stop() {
    echo -n $"Stopping $prog: "
    killproc $prog -QUIT
    retval=$?
    echo
    [ $retval -eq 0 ] && rm -f $lockfile
    return $retval
}

restart() {
    configtest || return $?
    stop
    start
}

reload() {
    configtest || return $?
    echo -n $"Reloading $prog: "
    killproc $nginx -HUP
    RETVAL=$?
    echo
}

force_reload() {
    restart
}

configtest() {
  $nginx -t -c $NGINX_CONF_FILE
}

rh_status() {
    status $prog
}

rh_status_q() {
    rh_status >/dev/null 2>&1
}

case "$1" in
    start)
        rh_status_q && exit 0
        $1
        ;;
    stop)
        rh_status_q || exit 0
        $1
        ;;
    restart|configtest)
        $1
        ;;
    reload)
        rh_status_q || exit 7
        $1
        ;;
    force-reload)
        force_reload
        ;;
    status)
        rh_status
        ;;
    condrestart|try-restart)
        rh_status_q || exit 0
            ;;
    *)
        echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload|configtest}"
        exit 2
esac

增加可执行文件并启动nginx

chmod +x /etc/init.d/nginx
/etc/init.d/nginx start

chkconfig --add nginx
chkconfig --level 345 nginx on

nginx_welcome

开启fastcgi, 编辑/etc/nginx/nginx.conf

location ~ \.php$ {
            root           html;
            fastcgi_pass   127.0.0.1:9000;
            fastcgi_index  index.php;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            include        fastcgi_params;
}

PHP-fpm

安装必要软件

yum -y install gcc automake autoconf libtool make gcc-c++ glibc install libmcrypt-devel mhash-devel libxslt-devel libjpeg libjpeg-devel libpng libpng-devel freetype freetype-devel libxml2 libxml2-devel zlib zlib-devel glibc glibc-devel glib2 glib2-devel bzip2 bzip2-devel ncurses ncurses-devel curl curl-devel e2fsprogs e2fsprogs-devel krb5 krb5-devel libidn libidn-devel openssl openssl-devel

下载php http://php.net/get/php-5.5.29.tar.bz2/from/a/mirror

wget http://cn2.php.net/get/php-5.5.29.tar.bz2/from/this/mirror
mv mirror php-5.5.29.tar.bz2
bunzip2 php-5.5.29.tar.bz2 
tar -xvf php-5.5.29.tar
cd php-5.5.29

开始编译,其中 –with-mysql=/app/mysql 是我的Mysql安装目录

./configure --prefix=/app/php  --enable-fpm --with-mcrypt --enable-mbstring --enable-pdo --with-curl --disable-debug  --disable-rpath --enable-inline-optimization --with-bz2  --with-zlib --enable-sockets --enable-sysvsem --enable-sysvshm --enable-pcntl --enable-mbregex --with-mhash --enable-zip --with-pcre-regex --with-mysql=mysqlnd --with-mysqli=mysqlnd --with-gd --with-jpeg-dir --enable-opcache --with-pdo-mysql

make && make install

如果出现错误:configure: error: mcrypt.h not found. Please reinstall libmcrypt.
需要安装mcrypt 2.5.8,一定是2.5.8

wget http://nchc.dl.sourceforge.net/project/mcrypt/Libmcrypt/2.5.8/libmcrypt-2.5.8.tar.gz
tar -zxvf libmcrypt-2.5.8.tar.gz 
cd libmcrypt-2.5.8
./configure
make && make install

opcache 出错?
configure: error: Don’t know how to define struct flock on this system, set –enable-opcache=no

vim /etc/ld.so.conf.d/local.conf     # 编辑库文件
/usr/local/lib                       # 添加该行,64位使用:/usr/local/lib64
                                     # 保存退出
ldconfig -v                          # 重新加载

复制php.ini和php-fpm.conf

cp php.ini-production /app/php/lib/php.ini
cp /app/php/etc/php-fpm.conf.default /app/php/etc/php-fpm.conf

配置php.ini, 编辑/app/php/lib/php.ini

display_errors = On
memory_limit = 1024M #根据个人情况来
date.timezone = Asia/Shanghai
post_max_size = 1000M
upload_max_filesize = 1000M
max_execution_time = 1000

[opcache]
opcache.enable=1
opcache.enable_cli=1
opcache.memory_consumption=128
opcache.interned_strings_buffer=4
opcache.max_accelerated_files=4000

配置php-fpm.conf, 编辑/app/php/etc/php-fpm.conf

user = nginx   #这里和上面nginx的用户对应起来
group = nginx

启动php-fpm

/app/php/sbin/php-fpm

#重启, 不支持重启,唯一的办法就是结束进程再启动
killall php-fpm
/app/php/sbin/php-fpm

编辑/etc/profile

export PATH=/app/php/bin:$PATH

测试

vim /app/nginx/html/index.php

phpinfo();

phptest

PHP 异步执行

执行整个文件, 这样就会在系统后台悄悄的执行你的php文件了. 当然还可以fsockeopen或者curl

exec("php cron.php > /dev/null &");
pclose(popen("php cron.php &", 'r'));

PHP文件大小格式化与反格式化

此代码来自drupal


define('DRUPAL_KILOBYTE', 1024);

/**
 * Parses a given byte count.
 *
 * @param $size
 *   A size expressed as a number of bytes with optional SI or IEC binary unit
 *   prefix (e.g. 2, 3K, 5MB, 10G, 6GiB, 8 bytes, 9mbytes).
 *
 * @return
 *   An integer representation of the size in bytes.
 */
function parse_size($size) {
  $unit = preg_replace('/[^bkmgtpezy]/i', '', $size); // Remove the non-unit characters from the size.
  $size = preg_replace('/[^0-9\.]/', '', $size); // Remove the non-numeric characters from the size.
  if ($unit) {
    // Find the position of the unit in the ordered string which is the power of magnitude to multiply a kilobyte by.
    return round($size * pow(DRUPAL_KILOBYTE, stripos('bkmgtpezy', $unit[0])));
  }
  else {
    return round($size);
  }
}

/**
 * Generates a string representation for the given byte count.
 *
 * @param $size
 *   A size in bytes.
 * @param $langcode
 *   Optional language code to translate to a language other than what is used
 *   to display the page.
 *
 * @return
 *   A translated string representation of the size.
 */
function format_size($size) {
  if ($size < DRUPAL_KILOBYTE) {
    return str_replace('@count bytes', '@count', $size);
  }
  else {
    $size = $size / DRUPAL_KILOBYTE; // Convert bytes to kilobytes.
    $units = array(
      '@size KB',
      '@size MB',
      '@size GB',
      '@size TB',
      '@size PB',
      '@size EB',
      '@size ZB',
      '@size YB',
    );
    foreach ($units as $unit) {
      if (round($size, 2) >= DRUPAL_KILOBYTE) {
        $size = $size / DRUPAL_KILOBYTE;
      }
      else {
        break;
      }
    }
    return str_replace('@size', round($size, 2), $unit);
  }
}

var_dump(format_size(2003330));

输入: 1.91KB