phar简介

2016年11月30日 没有评论

php5.3以后有一个非常不错的特性phar,有些类似java中的jar包,就是可以把php应用程序打包到一个单独的phar归档文件中。其实这个特性以前很早貌似就用,只不过最早是用php写的,所以性能上面不是特别好,后面官方用c扩展重新写一遍,文档可以查看Phar文档,不过目前90%的内容是英文的,下面我对介绍进行了一点简单翻译,当然英语水平一般,错误之处欢迎指正啊。

Phar简介

Phar扩展提供了一种将整个php应用放入一个单独文件被称为”phar”的归档,包更容易的发布和安装的解决方案。除了提供这种服务,phar扩展也提供了一种抽象化的文件格式的方法来创建和管理tar或者zip文件通过PharData类,很像Pdo提供了一种统一的接口来访问不同的数据库。和PDO不同之处,Pdo不能将数据在不同的数据库之间转换,Phar可以通过一行代码就可以在tar,zip和phar之间转换文件格式。查看Phar::convertToExecutable()示例。

phar是什么?phar归档文件最显著的特征是组合很多文件文件到一个单独的文件中。就像这样,一个phar文档提供了一种方式来发布一个完成的php应用程序在一个单独的文件中并且可以通过这个文件来运行它而无需解压到硬盘上。此外,phar归档文件也可以像其他php文件一样去被PHP执行,同时可以通过命令行和一台web服务器。Phar就像一种为PHP应用程序设计的拇指驱动器(U盘)。

Phar实现这些功能通过Stream Wrapper。一般来说,要使用一个在Phar归档中的php脚本文件,你可以用include。

函数介绍

可以参考另一篇关于phar函数手册的博客。

简单案例

这是一个比较简单的demo,希望通过这个能对phar有个比较初步的了解。

目录树如下:

|____build.php
|____config.json
|____extractPhar.php
|____lib
| |____class
| | |____empty.txt
| |____func.php
| |____stub.php
|____phar.phar
|____test_phar.php

build.php为生成phar归档文件的php脚本,config.json文件其实没什么用,extractPhar.php为解压phar到指定目录的脚本,lib目录下面就是测试用的库函数,phar.phar是用build.php生成的归档文件,test_phar.php是测试phar归档文件的脚本。下面我们一个一个的介绍这里面涉及到的脚本文件。

[build.php]

</pre>
<pre><?php</pre>
<pre>try{
    $phar = new Phar('phar.phar',0,'my.phar');
    $phar->buildFromDirectory(__DIR__.'/lib/');
    //$phar->buildFromDirectory(__DIR__.'/lib/',"/\.php/");
    $phar->addFile("config.json","config");
    $phar->setDefaultStub('stub.php','stub.php');
    $phar->compressFiles(Phar::GZ);
}catch (Exception $e){
    echo $e->getMessage();
}</pre>
<pre>

这里需要注意把php.ini 中的 phar.readonly 设为 0 以适合 Phar 对象. 否则, 将抛出PharException。

[func.php]

</pre>
<pre>function println($str){
    echo $str."\n";
}

function myFunc($input=__FILE__){
    println('Input File:'.$input);
    println('File Path:'.__DIR__);
}</pre>
<pre>

[stub.php]

</pre>
<pre><?php

require_once 'func.php';
myFunc(__FILE__);</pre>
<pre>

[test_phar.php]

</pre>
<pre><?php
include_once 'phar.phar';
include_once 'phar://my.phar/func.php';
myFunc(__FILE__);
$content = file_get_contents("phar://my.phar/config");
println($content);</pre>
<pre>

[extractPhar.php]

</pre>
<pre><?php
$phar = new Phar('phar.phar');
$phar->extractTo('./extract/');</pre>
<pre>

通过命令行脚本执行”php build.php”可以生成phar.phar归档文件。可以直接用”php phar.phar”执行phar归档文件,
它会执行”setDefaultStub”设置stub文件。extractPhar.php会将phar.phar归档文件中的内容解压到extract目录下面,
方面我们查看phar归档中的内容。
test_phar.php的执行结果如下:

Input File:phar:///Users/king/www/test/Phar/phar.phar/stub.php
File Path:phar:///Users/king/www/test/Phar/phar.phar
Input File:/Users/king/www/test/Phar/test_phar.php
File Path:phar:///Users/king/www/test/Phar/phar.phar
{
 "name" : "phar test project",
 "path" : "~/www/test/Phar"
}
extractPhar.php解压的extract目录如下:
|____class
| |____empty.txt
|____config
|____func.php
|____stub.php

ubuntu mysql5.7无法远程连接问题

2016年10月31日 没有评论

晚上在做联系xtrabackup时,实验环境是一台centos7和一台ubuntu 16.04的虚拟机,centos7上面安装的mysql在创建完远程连接账号以后可以正常登陆,但是ubuntu却无法登录,提示“ERROR 2003 (HY000): Can’t connect to MySQL server on ‘192.168.99.88’ (61)”。其实问题很简单,这里主要记录一下当时我解决问题的思路,当然当时思路不是很正确,以前也没有遇到过类似的问题。

第一时间我想到的是自己是不是把账号弄错了,ubuntu上面的mysql没有对应的账号(带上本机3台mysql难免会弄错),就用一个root账号在ubuntu上本地登录,然后查看当前的系统有哪些用户,发现自己登录用的远程账号和权限没有问题。


mysql -uroot -p

use mysql;

select * from user\G;

然后就是防火墙,是不是防火墙没有开启。那么就查看ubuntu的防火墙。


sudo iptables -L #查看防火墙规则列表

sudo iptables -F  #清空防火墙列表

做完这些还是无法登录,google了一下,发现是ubuntu系统下mysql的bind问题。ubuntu中mysql默认绑定的是127.0.0.1,这样就只允许本机登录,想要允许其他地方登录只需要把bind改成公网ip或者任何ip均可。

编辑mysql的配置文件”/etc/mysql/mysql.conf.d/mysqld.cnf”


#bind-address = 127.0.0.1
bind-address = 0.0.0.0

然后重启mysql,问题就解决了!

c语言函数指针

2016年10月18日 没有评论

最近在学习nginx相关的内容,看书上介绍nginx的源码,里面很多地方都用到了函数指针。对于我这种c语言菜鸟来说,看的是云里雾里的,搞不清楚要干嘛,就搜索了一些函数指针的内容,自己动手实验了一番。

在C系列语言中,任何一个变量,总是要先声明,之后才能使用的,这和php差别还是很大的。函数指针的声明可以按照如下”返回类型 (*变量名)(函数参数…)“进行,下面我来举几个例子。


void (*my_func1)(void);  //声明一个返回类型为空,参数为空,名字为my_func1的函数指针

int (*my_func2)(int x,int y);  //声明一个返回类型为整形,参数为整形x和整形y,名字为my_func2的函数指针

int (*my_func3)(int,int);   //声明一个返回类型为整形,参数为2个整形,名字为my_func3的函数指针,其实和上面的my_func2一样

void (*my_func4)(char *str);  //声明一个返回类型为空,参数为字符指针,名字为my_func4的函数指针

typedef void (*void_func_t)(void);  //typedef关键字是类型定义,这里就是定义了一个返回值为空,参数为空的函数指针类型,类型名称为void_func_t

相信经过上面的例子,对c语言的函数指针大家都有一个初步的概念,看了下面的代码相信大家基本都能初步掌握函数指针了.

文件名:main.c


#include <stdio.h>

//定义返回值为int,传入参数为2个int的函数指针
int (*point_func)(int,int);
int (*p_func)(int a,int b);
//定义返回值为int,传入参数为2个int的函数指针类型
typedef int (*sum_func)(int,int);

/**
 * 定义一个相加函数
 */
int sum(int x,int y){
 int r = x+y;
 printf("%d+%d=%d\n",x,y,r);
 return r;
}
//执行传入进去的函数
void exec_func(sum_func do_func){
 do_func(10,21);
}

int main() {
 int result;
 sum_func my_func;

my_func = sum;
 result = sum(1,2);
 point_func = &sum;
 p_func=point_func;
 //通过指针的方式调用函数
 (*point_func)(3,4);
 (*p_func)(5,6);
 p_func(7,8);
 exec_func(my_func);
 exec_func(point_func);
 return 0;
}


上面代码中我们既可以通过”(*p_func)(5,6)”也可以直接通过”p_func(7,8)”直接调用,前者是比较正规的写法,但是阅读起来是不是没有后者那么舒服顺畅。

编译上面代码”gcc main.c -o main”,执行代码就可以看到下面的输出结果:


1+2=3
3+4=7
5+6=11
7+8=15
10+21=31
10+21=31

 

centos7安装redis3.2

2016年9月27日 没有评论

最近在学习laravel框架,打算在虚拟机里面装个redis,使用yum安装时发现提供的版本是2.8。目前最新的版本是3.2,而3.0以后redis提供了cluster,对集群有很好的支持。在google了一番以后也没有找到redis3.2的源,于是就开始编译安装了。

redis官网下载最新版本的redis源码,然后开始编译安装,可以参考源码里面的README。


wget http://download.redis.io/releases/redis-3.2.4.tar.gz

tar -xvf redis-3.2.4.tar.gz

cd redis-3.2.4

cat README.md

make

make install

mkdir /etc/redis

cp utils/redis.conf /etc/redis/

redis-server /etc/redis/redis.conf

这时候用安装基本完成了,但是上面安装基本上按照默认的方式安装,但是有些地方可以自定义。比如redis安装位置,可以使用`make PREFIX=/some/other/directory install`,其中的“/some/other/directory”就是redis安装位置。

为了方面我们管理redis,我们可以写一个redis.service配置文件来方便我们管理redis。

这里我就给一个很简单的service配置文件例子:


[Unit]
Description=redis service file
Wants=network.target

[Service]
Type=forking
ExecStart=/usr/local/bin/redis-server /etc/redis/redis.conf
[Install]
WantedBy=multi-user.target

将上面的配置信息放入/lib/systemd/system/redis.service文件中,然后重新载入配置文件即可。还有一点就是需要修改/etc/redis/redis.conf中,将damonize改为yes,默认为no,即以守护进程的模式启动redis。


systemctl daemon-reload

#开机启动

systemctl enable redis.service

#启动redis

systemctl start redis.service

#关闭redis

systemctl stop redis.service

到此,redis的安装就完成了,可以使用redis-cli链接server了!

分类: Linux 标签:

php5.5新特性::class

2016年9月26日 没有评论

最近在了解laravel框架,发现它里面很多地方都使用了”类名::class”,这是php5.5以后新增的特性,功能有些类似get_class,不过get_class传入的是对象。

下面是官方手册中的描述和例子:

自 PHP 5.5 起,关键词 class 也可用于类名的解析。使用 ClassName::class 你可以获取一个字符串,包含了类 ClassName 的完全限定名称。这对使用了 命名空间 的类尤其有用。


<?php
namespace NS {
class ClassName {
}
echo ClassName::class;
}
?>

以上例程会输出:NS\ClassName.

我们可以拿它和get_class做一个比较:


<?php
NameSpace Test;

class Test{
}
var_dump(Test::class);
$t = new Test;
var_dump(get_class($t));

执行以后输出:

string(9) “Test\Test”
string(9) “Test\Test”

分类: PHP 标签:

mysql禁用validate-password插件

2016年8月17日 没有评论

近些版本的mysql做了很大的改动,在5.6.6以后的版本会开启validate-password插件。validate-password插件会对密码进行评估,如果不达标会提示你去进行修改.在生产环境这是非常不错的插件,弱口令就会消失,但是在开发环境就有些烦人了,谁都不想在每次等级都要输入一大串复杂的密码。所以我们可以选择降低validate-password对密码安全性的策略,或者直接就禁用它。

1 禁用validate-password

编辑my.cnf配置文件,在mysqld下面加入“validate-password=OFF”,然后重启mysql即可。

2 降低安全策略级别

首相我们来看一下validate-password相关的参数:

validate-password=ON/OFF/FORCE/FORCE_PLUS_PERMANENT: 决定是否使用该插件(及强制/永久强制使用)。

validate_password_dictionary_file:插件用于验证密码强度的字典文件路径。

validate_password_length:密码最小长度。

validate_password_mixed_case_count:密码至少要包含的小写字母个数和大写字母个数。

validate_password_number_count:密码至少要包含的数字个数。

validate_password_policy:密码强度检查等级,0/LOW、1/MEDIUM、2/STRONG。

validate_password_special_char_count:密码至少要包含的特殊字符数。

其中,关于validate_password_policy-密码强度检查等级:

0/LOW:只检查长度。

1/MEDIUM:检查长度、数字、大小写、特殊字符。

2/STRONG:检查长度、数字、大小写、特殊字符字典文件。

我们可以将安全策略降低为LOW,相信这样虽然还会有长度限制,但是已经足够简单了。

编辑my.cnf文件,在mysqld下面加入:


[mysqld]

validate_password_policy=LOW

然后重启mysql即可!

KMP字符串比较算法(php版本)

2016年7月5日 没有评论

前段时间面试的时候,被一个公司的人问到过,今天正好在地铁上面看到了关于KMP算法的文章,作者写的很好,我这个算法渣都看懂了!于是就抽空写了这个PHP版本的kmp算法实现,写的不好的地方欢迎指正。

<?php
/**
 * kmp字符串比较算法
 */

/**
 * 获得所有前缀集合
 * @param string $string
 *
 * @return array
 */
function get_prefix_set($string){
    $len = strlen($string);
    if($len <= 1 ) return [];
    $prefixs = [];
    for($i=1;$i<$len;$i++){
        $prefixs[] = substr($string,0,$i);
    }
    return $prefixs;
}

/**
 * 获得所有后缀集合
 * @param string $string
 *
 * @return array
 */
function get_suffix_set($string){
    $len = strlen($string);
    if($len<=1) return [];
    $suffixs = [];
    for($i=1;$i<$len;$i++){
        $suffixs[] = substr($string,$i);
    }
    return $suffixs;
}

/**
 * 查找字符串$str2是否在$str1中出现
 * @param string $str1
 * @param string $str2
 *
 * @return bool
 */
function my_strstr($str1,$str2){
    $prefixSet = get_prefix_set($str2);
    $suffixSet = get_suffix_set($str2);
    $intersection = array_intersect($prefixSet,$suffixSet);
    $matchValue = 0;
    if(!empty($intersection)){
        foreach($intersection as $tmpstr){
            $len = strlen($tmpstr);
            if($len>$matchValue) $matchValue = $len;
        }
    }
    $str1_len = strlen($str1);
    $str2_len = strlen($str2);
    $endPos = $str1_len-$str2_len;
    if($endPos<0){
        return false;
    }
    for($i=0;$i<=$endPos;){
        $moveStep = 1;
        for($n=0;$n<$str2_len;$n++){
            if($str1[$i+$n] != $str2[$n]){//字符串不匹配时,跳出本次循环
                $moveStep = $n-$matchValue;
                $moveStep = $moveStep > 0 ? $moveStep : 1;
                break 1;
            }else if($str1[$i+$n] == $str2[$n] && $n==$str2_len-1){
                return true;
            }
        }
        $i +=$moveStep;
    }
    return false;
}

$result = my_strstr("abcabfcde","bfcd");
var_dump($result);

如果对KMP算法不是特别了解可以看一下《字符串匹配的KMP算法》

mysql重置root密码

2016年4月14日 没有评论

今天在mac上面安装mysql,安装之后用root登录,发现进不去,说需要密码,使用DMG包安装时提示我生成的随机密码也尝试了,依旧不行!不过生成root密码页面提示如果无法登录可以尝试查看How to Reset the Root Password,进行重置root密码工作。如果你觉得自己英文还行可以直接参考前面那个连接去查看,好了,下面进入正题重置密码。

我是在mac下面做的重置root操作,不过windows下面的很类似,本文的必要条件是你有管理mysql服务器账号或者在本机上面,如果上面2个都不满足,那么这篇文章就不适合你了。

第一步关闭正在运行mysql服务器。

官网手册的命令是这样的,不过你可以像我这样通过ps查看mysql的进程id,然后kill它,当然这里最好把ps中启动mysql的命令先记录下来,后面会使用的。

kill `cat /mysql-data-directory/host_name.pid`
#ps方法
ps aux|grep 'mysql'
#这里把%pid%替换为上面ps给的进程id
sudo kill %pid%

第二步建立mysql init文件
这一步是要建立一个mysql init文件,配合mysqld的–init-file参数来使用的.init-file参数英文说明是”Read SQL commands from this file at startup”,我的个人理解是读取指定文件中的sql语句,并在mysql启动的时候执行它们。
mysql版本5.7.6和以后使用”ALTER USER ‘root’@’localhost’ IDENTIFIED BY ‘MyNewPass’;”,如果你的版本是其他版本可以使用”SET PASSWORD FOR ‘root’@’localhost’ = PASSWORD(‘MyNewPass’);”尝试一下。

#5.7.6和以后版本
ALTER USER 'root'@'localhost' IDENTIFIED BY 'MyNewPass';
#5.7.6以前版本
SET PASSWORD FOR 'root'@'localhost' = PASSWORD('MyNewPass');

保存文件。
第三步重启mysql
这时候我们来重启我们的mysql,不过是加上–init-file参数的命令。还记得我上面让你记住的ps下面的mysql启动命令吧,就是这里用的。官方手册是”mysqld_safe –init-file=/home/me/mysql-init &”,也许在其他类*unix系统上面可以,但是我在mac下面尝试了,启动不起来!如果你是centos或者ubuntu用户可以尝试一下官方手册的命令,不过mac下面还是建议使用ps中显示的命令,再后面追加–init-file参数。


#官网手册命令,mac用户不推荐

mysqld_safe --init-file=/home/me/mysql-init &

#mac用户推荐命令

sudo /usr/local/mysql/bin/mysqld --user=_mysql --basedir=/usr/local/mysql --datadir=/usr/local/mysql/data --plugin-dir=/usr/local/mysql/lib/plugin --log-error=/usr/local/mysql/data/mysqld.local.err --pid-file=/usr/local/mysql/data/mysqld.local.pid --init-file=/Users/king/sql/alter_root.sql &

“/Users/king/sql/alter_root.sql”为你第二步是保存的sql文件.此时再使用root用户用你重置的命令登录就可以成功登录了!

windows下面的重置root密码功能应该和mac下面类似,只要把shell命令换成dos命令即可,具体的可以参考上面的官网手册地址。

==2016-9-26号补更============================================================================

前几天在虚拟机里面装了mysql5.7.15,装完以后用root空密码登录失败.于是就用上面的方法重置密码,发现它并没有mysqld_safe文件,于是上面的方法就不是很适用了,就把重新查找了些资料,花了好久才解决!

我在stackoverflow上面找到了一种解决办法:

1. 停止mysql服务:
systemctl stop mysqld

2. 设置mysql的环境变量参数 
systemctl set-environment MYSQLD_OPTS="--skip-grant-tables"

3. 启动mysql服务
systemctl start mysqld

4. root无密码登录
mysql -u root

5. 更新root密码
mysql> UPDATE mysql.user SET authentication_string = PASSWORD('MyNewPassword')
    -> WHERE User = 'root' AND Host = 'localhost';
mysql> FLUSH PRIVILEGES;
mysql> quit

6. 关闭mysql服务
systemctl stop mysqld

7. 删除mysql环境参数
systemctl unset-environment MYSQLD_OPTS

8. 再次启动:
systemctl start mysqld

9. 用root登录:
. mysql -u root -p
当然可以把

skip-grant-tables写到”my.cnf”中重启mysql也可达到同样的目的!

centos安装EPEL源

2016年4月7日 没有评论

在虚拟机里面使用我的one_shell_install_lnmp脚本安装lnmp环境的时候,发现报错了,提示缺少libmcrypt-devel包。以前我是在centos7下面测试过我的脚本的,是可以通过的,于是我就又检查了一下脚本,里面有安装libmcrypt-devel 这个选项。我又试着单独执行了一下安装libmcrypt-devel包的命令,依然是没有任何反应。刚开始我第一时间没有想到源的问题,类似以往的习惯去google,发现也有同学和我类似,说163源上面没有libmcrypt-devel这个包,于是就有了今天这个文章。当然这篇文章是笔记性质的,如果对你有帮助,十分荣幸,有问题也可以留言。

EPEL是什么

EPEL全名是Extra Packages for Enterprise Linux(epel wiki:https://fedoraproject.org/wiki/EPEL),是一个由特别兴趣小组创建、维护并管理的,针对 红帽企业版 Linux(RHEL)及其衍生发行版(比如 CentOS、Scientific Linux、Oracle Enterprise Linux)的一个高质量附加软件包项目。

其实我也是今天才了解的EPEL,以前虽然使用过它,但是对它没有什么系统了解,上面介绍它的内容也是摘自wiki。

EPEL安装

我写了一个install_epel.sh的shell脚本, 功能就是检测当前系统是否有epel源,如果不存在就安装。


#!/bin/bash

#检查epel源是否安装
yum repolist|egrep "epel" >& /dev/null
if [ $? -ne 0 ];then
epel_file="epel.noarch.rpm"
wget http://dl.fedoraproject.org/pub/epel/7/x86_64/e/epel-release-7-5.noarch.rpm -O $epel_file
rpm -ivh $epel_file
rm -f $epel_file
yum makecache
fi

关于yum或者epel其他介绍,请自行google!

分类: Linux 标签: ,

Systemd配置文件service小解

2015年11月30日 没有评论

最早看到systemd还是在微博上面看到陈浩在回答别人如何解决死掉的进程如何重启的,陈浩说systemd这个“神器”可以轻松解决这个问题。在那之前我对systemd还是一无所知的,所以特意google了一下systemd到底是个神马东西。

网上对systemd的评价毁誉参半,抵制systemd说它不稳定有时候可能crash,或者说脚本从原始Sysvinit移植到systemd会花费运维人员大量的时间(包含systemd的学习时间)之类的,甚至有人拿出来Unix的哲学“ do one thing and do it well”,说systemd做了系统启动等等很多工作,不见得都能把它做好。对于这些种种理由,我觉得没必要一一反击,看看这一篇《浅析 Linux 初始化 init 系统,第 3 部分: Systemd》。当然我觉得对开发和运维人员非常有必要学习systemd的原因是redhat7系列(centos7),debian系列等等linux主要衍生版本在他们的新版本中都在转投systemd怀抱,所以如果你是linux系统的使用者,我觉得学习了解systemd还是非常非常有必要的。

service配置样例

这是一个简单的脚本启动,进程终止以后会自动重启!

[Unit]
Description=a php im push script
Wants=network.target

[Service]
Type=simple
ExecStart=/path/to/your/script
Restart=always

[Install]
WantedBy=multi-user.target

Description是对服务的描述,方便记忆和阅读,一般来说这里可以随心所欲的。
Wants是服务项的启动依赖那些项。
Type是服务的类型,有simple,forking,oneshot,dbus,notify,idle。其中我们常用的类型有simple,forking,oneshot。simple 是默认,这是最简单的服务类型。意思就是说启动的程序就是主体程序,这个程序要是退出那么一切都退出。forking 标准 Unix Daemon 使用的启动方式。启动程序后会调用 fork() 函数,把必要的通信频道都设置好之后父进程退出,留下守护精灵的子进程。oneshot种服务类型就是启动,完成,没进程了。
ExecStart是启动脚本的路径和参数,参数和脚本之间用空格分割。
Restart是配置启动项是否需要重启,有no,on-success,on-failure,on-abnormal,on-watchdog,on-abort,always。这些选项就是他们字面意思,abnormal意思是反常的,看文档里面说除了信号SIGHUP,SIGINT,SIGTERM,SIGPIPE以外其他信号终止的,都是反常的包含code dump,操作超时等。
WantBy指服务在何种情况下面会被启动,例如上面multi-user.target指的是多用户环境。
当然我觉得这几个简单的配置项几乎就可以解决我们日常60%的问题了,其他特殊的需求可以查看文档。
如果你的英文还不错,可以查看下面2个英文手册,service手册unit手册

分类: Linux 标签: