/usr/bin/env: PHP: No such file or directory报错
su www

[root@VM-0-15-centos ~]# curl -sS https://getcomposer.org/installer | php

#把composer.phar转移之bin目录以便全局使用
[root@VM-0-15-centos ~]# mv composer.phar /usr/local/bin/composer
#展示版本信息说明成功
[root@VM-0-15-centos ~]# composer -v
如果出现这个提示,是因为composer不建议root账号运行,可以输入y,或者切换账号

Do not run Composer as root/super user! See https://getcomposer.org/root for details
Continue as root/super user [yes]?

sudo -u www -H/usr/local/composer/bin/composer config repo.packagist composer https://mirrors.aliyun.com/composer/
[ErrorException]
  touch(): Unable to create file /home/www/.config/composer/config.json because No such file or directory  

#composer clear-cache
Do not run Composer as root/super user! See https://getcomposer.org/root for details
Continue as root/super user [yes]? yes
Cache directory does not exist (cache-vcs-dir):
Cache directory does not exist (cache-repo-dir):
Cache directory does not exist (cache-files-dir):
Clearing cache (cache-dir): /root/.cache/composer
如果是其它用户就是在它的家目录下面建立配置文件。

[root@nexus-repo-10-10-0-109:/data/www/l.levoo.com]
#sudo -u www -H /usr/local/composer/composer update
Loading composer repositories with package information

[root@nexus-repo-10-10-0-109:/data/www/l.levoo.com]
#sudo -u www -H /usr/local/composer/composer update
......
Package operations: 41 installs, 14 updates, 38 removals
    Failed to download dragonmantank/cron-expression from dist: The zip extension is missing and unzip/7z commands cannot be called as proc_open is disabled, skipping.
Your command-line PHP is using multiple ini files. Run `php --ini` to show them.
    Now trying to download from source

PHP的一些安全函数禁用了,打开就成功了:
  - Upgrading easyswoole/task (1.0.5 => 1.1.2): Extracting archive
  - Upgrading easyswoole/log (1.0.3 => 1.1.1): Extracting archive
Generating autoload files
28 packages you are using are looking for funding.
Use the `composer fund` command to find out more!



然后执行compser up
或者备份composer.lock
==========================================================================

composer config -g repo.packagist composer https://packagist.phpcomposer.com #换国内镜像URL地址。
composer是一个可执行命令,你在一个空目录下写一个composer.json
然后执行composer update,就能生成。
====================两步:软链接composer/PATH/下载autoloader===========================
软链接加PATH:


easy swoole 3.0.9 官方并不是最新的,换换阿里云镜像:
全局替换:
composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/
composer clear-cache # 此步奏选泽性操作,清除所有 package 缓存。
composer clear-cache
Cache directory does not exist (cache-vcs-dir):
Clearing cache (cache-repo-dir): /data/www/.cache/composer/repo
Clearing cache (cache-files-dir): /data/www/.cache/composer/files
Clearing cache (cache-dir): /data/www/.cache/composer

当前项目替换: (注意:不让root用户运行,用www用户)
cd 项目目录
composer config repo.packagist composer https://mirrors.aliyun.com/composer/


不重新开终端不会生效,则可直接导入变量:
source /etc/profile.d/composer.sh


cd /usr/local/kafka-php
cat composer.json
{
        "require": {
                "nmred/kafka-php": "0.2.*"
        }
}

composer update
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 3 installs, 0 updates, 0 removals
  - Installing amphp/amp (v1.2.2): Downloading (100%)        
  - Installing psr/log (1.0.2): Downloading (100%)        
  - Installing nmred/kafka-php (v0.2.0.8): Downloading (100%)        
Writing lock file
Generating autoload files

cd /usr/local/kafka-php
composer.json  composer.lock  vendor
目的是看下同事所说的Kafka死光了,kafka-php会退出的问题:
https://github.com/weiboad/kafka-php

===========================================================================

cd /usr/local/composer  ,sudo -u www -H composer.phar install ,会去读取:/usr/local/composer/composer.json文件。
chown -R www.www /data/htdocs/sd.levoo.com #否则会报:/data/htdocs/sd.levoo.com/vendor does not exist and could not be created.
sudo -u www -H composer.phar install

实践如下:


vi /etc/sudoers
Defaults    secure_path = /sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin:/usr/local/mysql/bin:/usr/local/composer:/usr/local/php/bin


#sudo -u www -H composer.phar config -g repo.packagist composer https://packagist.phpcomposer.com                                                                                                    
  [ErrorException]                                                                                  
  touch(): Unable to create file /home/www/.composer/config.json because No such file or directory  

#mkdir  /home/www
#chown www.www /home/www
#chmod 755 /home/www
#sudo -u www -H composer.phar config -g repo.packagist composer https://packagist.phpcomposer.com


#sudo -u www -H composer.phar install
Composer could not find a composer.json file in /usr/local/composer
To initialize a project, please create a composer.json file as described in the https://getcomposer.org/ "Getting Started" section

建立composer.json如下,可以根据需要添加你所依赖的库,但下面一定得包含在内,autoload必须要指定app和test的目录不得省略。

{
  "require": {
    "tmtbe/swooledistributed":">2.0.0"
  },
"autoload": {
    "psr-4": {
      "app\\": "src/app",
      "test\\": "src/test"
    }
  }
}
/usr/local/composer/composer.json
运行:
#sudo -u www -H composer.phar install
Loading composer repositories with package information
Updating dependencies (including require-dev)
  [RuntimeException]                                                  
  /usr/local/composer/vendor does not exist and could not be created.

  [RuntimeException]                                                                
  /usr/local/composer/vendor/symfony/intl does not exist and could not be created

  - Installing symfony/intl (v3.3.8):
                                                                                          
  [Symfony\Component\Process\Exception\RuntimeException]                                  
  The Process class relies on proc_open, which is not available on your PHP installation.  
      
PHP需有proc_open,得从PHP的php.ini里给去掉:
; disable_functions = chroot,chgrp,chown,shell_exec,proc_open,proc_get_status,ini_alter,ini_
restore,dl,openlog,syslog,readlink,symlink,popepassthru,stream_socket_server,fsocket

#sudo -u www -H composer.phar install
Composer could not find a composer.json file in /usr/local/php/etc
To initialize a project, please create a composer.json file as described in the https://getcomposer.org/ "Getting Started" section
得cd到:/usr/local/composer 里,再执行:sudo -u www -H composer.phar install
#sudo -u www -H composer.phar install
  [ErrorException]                                          
  proc_get_status() has been disabled for security reasons   和上面一样:得从PHP的php.ini里给去掉。
  [RuntimeException]                                          
  Could not delete /usr/local/composer/vendor/symfony/intl:
  chown -R www.www  /usr/local/composer/vendor
  [ErrorException]                                                              
  file_put_contents(./composer.lock): failed to open stream: Permission denied   #写入/usr/local/composer/composer.lock权限不够。
[root@gitlab-jenkins_php-redis_123.57.252.183:/usr/local]
#chown www.www composer
#sudo -u www -H composer.phar install
Loading composer repositories with package information
Updating dependencies (including require-dev)
Nothing to install or update
Writing lock file
Generating autoload files
。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。


From:https://getcomposer.org/download/
http://blog.csdn.net/yoywow/article/details/52074512

二、使用composer安装laravel/lumen:
遇到问题:
修改 composer 的全局配置文件(推荐方式)

打开命令行窗口(windows用户)或控制台(Linux、Mac 用户)并执行如下命令:
[root@a composer]# chtdocs
[root@a htdocs]# cd lumen.levoo.com/
[root@a lumen.levoo.com]# /usr/local/composer/composer.phar global require "laravel/lumen-installer"
Changed current directory to /root/.config/composer
Do not run Composer as root/super user! See https://getcomposer.org/root for details
compser 执行命令提示do not run composer as root/super !
这个是因为composer为了防止非法脚本在root下执行,解决办法随便切换到非root用户即可
su www
mkdir -p /home/www/.cache
chown -R www:www /home/www/.cache

composer require easyswoole/hot-reload
Cannot create cache directory /home/www/.cache/composer/repo/https---mirrors.aliyun.com-composer/, or directory is not writable. Proceeding without cache
Cannot create cache directory /home/www/.cache/composer/files/, or directory is not writable. Proceeding without cache
Using version ^0.1.2 for easyswoole/hot-reload
./composer.json has been updated


PATH变量设置Ok的方法如下:
打开~/.bashrc
sudo vim ~/.bashrc
添加行:
export PATH=$PATH:/home/lumen/.config/composer/vendor/bin


用Linux系统。比如要把/etc/apache/bin目录添加到PATH中,方法有三:
1.#PATH=c/etc/apache/bin
使用这种方法,只对当前会话有效,也就是说每当登出或注销系统以后,PATH 设置就会失效

2.#vi /etc/profile
在适当位置添加 PATH=$PATH:/etc/apache/bin (注意:= 即等号两边不能有任何空格)
这种方法最好,除非你手动强制修改PATH的值,否则将不会被改变

3.#vi ~/.bash_profile
修改PATH行,把/etc/apache/bin添加进去
这种方法是针对用户起作用的
From:http://opsmysql.blog.51cto.com/2238445/665990


lumen没有成功:



useradd lumen
su lumen
cd /data/htdocs/laravel.levoo.com
/usr/local/composer/composer.phar  config -g repo.packagist composer https://packagist.phpcomposer.com


进行上述设置后,laravel有门,能下载了:
[lumen@a laravel.levoo.com]$ pwd
/data/htdocs/laravel.levoo.com
[lumen@a laravel.levoo.com]$ /usr/local/composer/composer.phar global require "laravel/lumen-installer"  
Changed current directory to /home/lumen/.config/composer
Using version ^1.0 for laravel/lumen-installer
./composer.json has been created
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 10 installs, 0 updates, 0 removals
  - Installing symfony/process (v3.2.1) Downloading: 100%        
  - Installing psr/log (1.0.2) Downloading: 100%        
  - Installing symfony/debug (v3.2.1) Downloading: 100%        
  - Installing symfony/polyfill-mbstring (v1.3.0) Downloading: 100%        
  - Installing symfony/console (v3.2.1) Downloading: 100%        
  - Installing guzzlehttp/promises (v1.3.1) Downloading: 100%        
  - Installing psr/http-message (1.0.1) Downloading: 100%        
  - Installing guzzlehttp/psr7 (1.3.1) Downloading: 100%        
  - Installing guzzlehttp/guzzle (6.2.2) Downloading: 100%        
  - Installing laravel/lumen-installer (v1.0.2) Downloading: 100%        
symfony/console suggests installing symfony/event-dispatcher ()
symfony/console suggests installing symfony/filesystem ()
Writing lock file
Generating autoload files


生成文件如下:
[lumen@a composer]$ pwd
/home/lumen/.config/composer

[lumen@a composer]$ ls  /home/lumen/.config/composer
auth.json  composer.json  composer.lock  config.json  vendor


开始学习数据库:
http://blog.csdn.net/wowkk/article/details/52104689

/data/htdocs/lumen.levoo.com/blog/.env
APP_ENV=local
APP_DEBUG=true
APP_KEY=
APP_TIMEZONE=UTC

DB_CONNECTION=mysql
DB_HOST=10.44.202.177
DB_PORT=3306
DB_DATABASE=levoo_egg
DB_USERNAME=levoo
DB_PASSWORD=new@levoo.com

CACHE_DRIVER=memcached
QUEUE_DRIVER=sync

/data/htdocs/lumen.levoo.com/blog/app/Http/Controllers/AccountController.PHP


/data/htdocs/lumen.levoo.com/blog/routes/web.php
<?php

$app->group(["namespace"=>"App\Http\Controllers"], function()use($app){
    //账户控制器
    $app->get("/AccountController",["uses" => "AccountController@accountController"]);
});


model:/data/htdocs/lumen.levoo.com/blog/app/Models/User.php
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;
class User extends Model
{
}



在app/Http/Controllers目录下AccountController.php,修改为

<?php

namespace App\Http\Controllers;

use App\user;   //新增部分
use Laravel\Lumen\Routing\Controller as BaseController;
use Illuminate\Http\Request;

class AccountController extends BaseController
{
    //直接传人sql方式操作数据库
    function accountController(Request $request){
        return User::all();
    }
}

http://101.200.189.210/AccountController/accountController


调试栏(Laravel Debug Bar)
PHP调试栏项目无疑是一个巨大的成功,你无需到处编写var_dump。Laravel调试栏对该组件作了扩展,包含了路由、视图、事件以及更多信息。
这使得调试变得更加简单、快速,提高你的开发效率。

Confide
认证模块,包含了登录、注册、退出、密码重置等功能。

代码生成器(Laravel Generators)
使用简单的命令行就可以自动根据代码模板生成Model/View/Controller代码以及模块(Module)。


HTML压缩器(Laravel HTML Minify)
让你的页面减小大概18%,提升性能必备

后台管理(Laravel Administrator)
Laravel Administrator帮助开发者快速构建后台管理界面,无需重复构建。

OAuth 4 Laravel:OAuth支持
OAuth 2服务器:安全和100%标准兼容的OAuth服务器

摘自下载量最高的 100 个 Laravel 扩展包推荐:
https://laravel-china.org/topics/2530

阅读全文
背景:像做点PHP给那个下位机,也就是现在的物联网芯片发送指令这种,用到这样的一个串,发送下去后,下位机解析后(解析到串里部分值修改后原样返回)再以串返回,自己想对串里作修改啥的用到这种url参数结构,如:framefd=4&fd=1&act=display&command=gettemp,解析在数组,同数组里的key=>value再解析成串。
parse_url
parse_str




From:http://www.cnblogs.com/freespider/p/4262244.html
背景:像做一些标识位、状态位,在早期的c语言或c++里都是通过一个位运算符来做的,这块PHP也在上面作了一些借鉴,对于爱放在数据库里和从数据库取东西的php程序,如果状态位很多,你想多个数据库表字段实现是不灵活的,哪天再来一个状态怎么办?所以,本文的思想就是用位运算达到灵活性之目的,故而转载此文。

PHP中的位运算和进制是比较冷门的知识,感觉很简单也很好理解,但是在实际场景中却很少使用,本篇博文就是简单了解基本概念以及讲解如何去实际使用.
位运算
PHP中的位运算符是对整形进行的操作,比如对于十进制,二进制,八进制等数字的一些操作.
& (按位与 AND)
| (按位或 OR)
~ (按位取反 NOT)
^ (按位异或 XOR)
<< (bitwise left shift)
>> (bitwise right shift)
下面用一个实际例子来说明如何去使用它们,比如一个博客系统最重要的元素就是文章,而文章可以有很多状态,比如状态可以是删除,评论,收藏,喜欢,当然可以根据实际情况扩展,那在数据库表中如何进行设计呢?假如通过每个字段来存储文章的状态,一方面表的可扩展性很差,另外一方面查询效率很差.
这个时候可以通过一个status字段来保存这些状态,这个字段的类型是整形,可以存储十进制,八进制,二进制,十六进制.
那么这么多状态`如何在一个字段值中表示呢,可以进行如下规定:
整数(二进制)  状态  说明
0001  删除状态  第一位等于1
0010  评论状态  第二位等于1
0100  收藏状态  第三位等于1
1000  喜欢状态  第四位等于1
面临的第一个问题,如何给文章增加状态属性?
$status = $status | 0b0001 ; //文章被置为删除状态$status = $status | 0b0010 ; //文章被置为评论状态$status = $status | 0b1100 ; //文章同时被置为收藏和喜欢状态
面临的第二个问题,如何给文章取消状态属性?
$status = $status & ~0b0001 ; //文章从删除状态恢复$status = $status & ~0b0010 ; //文章从评论状态恢复$status = $status & ~0b1100 ; //文章同时从收藏和喜欢状态恢复
面临的第三个问题,如何检查文章的状态?
$status & 0b0001?true:false ; //查询文章是否是删除状态$status & 0b0010?true:false ; //查询文章是否是评论状态$status & 0b1100?true:false ; //查询文章是否是收藏和喜欢状态
希望通过上面的例子你能明白位运算符的作用,另外位运算符和逻辑运算符比较容易让人误解.可以这样去区分和理解:
位运算符是对两个整数的bits进行操作,然后返回结果,That means it's not a yes or no thing.
假如位运算符被用在条件语句中,他们将会进行逻辑比较.
逻辑操作符是比较多个表达式,然后返回true或者false.
进制运算
上面位运算符的例子中,作为操作符数的都是二进制,但是也可以是其它进制.
PHP中支持二进制(binary),八进制(octal),十进制(decimal),十六进制(hexadecimal).
它们都是整型,进制和编码密切相关,这里仅仅说明PHP中的进制是如何表达的,以及之间是如何转换的.
如何在整型变量定义进制:
$n = 0b10000 ; //二进制$n = 16; //十进制$n = 0x10; //十六进制$n = 020;//八进制在echo输出的时候,不管是什么类型的整数,最后输出的都是十进制
定义字符串的时候如何通过进制表示:
//\[0-7]{1,3} #八进制表达方式//\x[0-9A-Fa-f]{1,2} #十六进制表达方式$str = "\20";$str = "\x10";echo输出的时候,会输出字符DLE
PHP内部函数如何支持进制转换,共有二种转换方式:
$n = 16;echo dechex($n) . "_" . decbin($n);$n = base_convert('10',16,10 ); //'10'本身的进制由第二个参数决定$nn = base_convert($n, 10,2 );echo $n . "_" . $nn ;//以上的函数返回各进制的字符串表达形式,那么如何返回这些变量代表的字符呢.echo  chr(base_convert('10',16,10 ));
sprintf如何在进制中使用:
这个函数实际上和进制没有非常耦合的关系,可以将不同进制的整型转换为不同进制的字符串表示
$n = sprintf("%x",  0b10000 );$n = sprintf("%x",  0x10 );$n = sprintf("%x",  020 );$n = sprintf("%x", 16 );$n = sprintf("%x", "a" );$n = sprintf("%s",  0b10000 );$n = sprintf("%c",  0b10000 );#返回ASCII值对应的字符

摘自:https://buluo.qq.com/p/detail.html?bid=13609&pid=5730935-1481030480&from=grp_sub_obj
背景:PHP5.5 在centos6 64位下编译报错,之前在另一台rpmbuild机上不存在这个问题。


解决办法:

vim /etc/ld.so.conf.d/local.conf     # 编辑库文件
/usr/local/lib                       # 添加该行
:wq                                  # 保存退出
ldconfig -v                          # 使之生效

注意事项:
这里添加的库文件路径一定要和你系统平台arch一致,32bit的系统直接添加/usr/local/lib即可,64bit系统要填加/usr/local/lib64.否则依旧会报错,我当时就是添加了/usr/local/lib死活编辑不了,后来更改为
/usr/local/lib64才可以。切记

http://lovelace.blog.51cto.com/1028430/1314571
背景:阿里搞的lvs,在七层交换时出现获取不到正确的remote_addr的情况,昨天那个取不到remote_ip的把lvs修改成4层交换就O了,可以通过$ip=$_SERVER["REMOTE_ADDR"]; 获取到用户端的出口IP的。


(1).REMOTE_ADDR:浏览当前页面的用户计算机的ip地址

(2).HTTP_X_FORWARDED_FOR: 浏览当前页面的用户计算机的网关

(3).HTTP_CLIENT_IP:客户端的ip

在PHP 中使用 $_SERVER["REMOTE_ADDR"] 来取得客户端的 IP 地址,但如果客户端是使用代理服务器来访问,那取到的就是代理服务器的 IP 地址,而不是真正的客户端 IP 地址。要想透过代理服务器取得客户端的真实 IP 地址,就要使用 $_SERVER["HTTP_X_FORWARDED_FOR"] 来读取。

不过要注意的事,并不是每个代理服务器都能用 $_SERVER["HTTP_X_FORWARDED_FOR"] 来读取客户端的真实 IP,有些用此方法读取到的仍然是代理服务器的 IP。

还有一点需要注意的是:如果客户端没有通过代理服务器来访问,那么用$_SERVER["HTTP_X_FORWARDED_FOR"] 取到的值将是空的。
来自:http://www.jb51.net/article/27880.htm
更详细的解释如下:


REMOTE_ADDR 是你的客户端跟你的服务器“握手”时候的IP。如果使用了“匿名代理”,REMOTE_ADDR将显示代理服务器的IP。
HTTP_CLIENT_IP 是代理服务器发送的HTTP头。如果是“超级匿名代理”,则返回none值。同样,REMOTE_ADDR也会被替换为这个代理服务器的IP。
$_SERVER['REMOTE_ADDR']; //访问端(有可能是用户,有可能是代理的)IP
$_SERVER['HTTP_CLIENT_IP']; //代理端的(有可能存在,可伪造)
$_SERVER['HTTP_X_FORWARDED_FOR']; //用户是在哪个IP使用的代理(有可能存在,也可以伪造)

三个值区别如下:

一、没有使用代理服务器的情况:

REMOTE_ADDR = 您的 IP
HTTP_VIA = 没数值或不显示
HTTP_X_FORWARDED_FOR = 没数值或不显示

二、使用透明代理服务器的情况:Transparent Proxies

REMOTE_ADDR = 最后一个代理服务器 IP
HTTP_VIA = 代理服务器 IP
HTTP_X_FORWARDED_FOR = 您的真实 IP ,经过多个代理服务器时,这个值类似如下:203.98.182.163, 203.98.182.163, 203.129.72.215。

这类代理服务器还是将您的信息转发给您的访问对象,无法达到隐藏真实身份的目的。

三、使用普通匿名代理服务器的情况:Anonymous Proxies

REMOTE_ADDR = 最后一个代理服务器 IP
HTTP_VIA = 代理服务器 IP
HTTP_X_FORWARDED_FOR = 代理服务器 IP ,经过多个代理服务器时,这个值类似如下:203.98.182.163, 203.98.182.163, 203.129.72.215。

隐藏了您的真实IP,但是向访问对象透露了您是使用代理服务器访问他们的。

四、使用欺骗性代理服务器的情况:Distorting Proxies

REMOTE_ADDR = 代理服务器 IP
HTTP_VIA = 代理服务器 IP
HTTP_X_FORWARDED_FOR = 随机的 IP ,经过多个代理服务器时,这个值类似如下:203.98.182.163, 203.98.182.163, 203.129.72.215。

告诉了访问对象您使用了代理服务器,但编造了一个虚假的随机IP代替您的真实IP欺骗它。

五、使用高匿名代理服务器的情况:High Anonymity Proxies (Elite proxies)

REMOTE_ADDR = 代理服务器 IP
HTTP_VIA = 没数值或不显示
HTTP_X_FORWARDED_FOR = 没数值或不显示 ,经过多个代理服务器时,这个值类似如下:203.98.182.163, 203.98.182.163, 203.129.72.215。

完全用代理服务器的信息替代了您的所有信息,就象您就是完全使用那台代理服务器直接访问对象。

//获取用户IP
$ip = '';
foreach (array('HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_FROM', 'REMOTE_ADDR') as $v) {
   if (isset($_SERVER[$v])) {
       if (! preg_match('/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/', $_SERVER[$v])) {
                continue;
   }
          $ip = $_SERVER[$v];
   }
}

uset($ip,$v);

来自:http://www.cnblogs.com/jackluo/archive/2013/03/03/2941411.html
背景:看PHP的慢日志一般来讲主要是看网络接口上的问题,有时间一台服务器会调用api接口,而该接口呢在另一吧机器上,而有人恶意透过这个接口频繁调用,飙高带宽,进而导致一堆TIME_WAIT,nginx出现白页,此时,这是现象,如何由现象看到本质,那就打开php-fpm的slow的日志吧,如何打开,接着向下看吧。
——————————————————————————————————————————————————————————————————————
众所周知,mysql有slow query log,根据慢查询日志,我们可以知道那些sql语句有性能问题。作为mysql的好搭档,php也有这样的功能。如果你使用php-fpm来管理php的话,你可以通过如下选项开启。
PHP 5.3.3 之前设置如下:
<value name="request_slowlog_timeout">5s</value>
<value name="slowlog">logs/php-fpm-slowlog.log</value>

说明:
request_slowlog_timeout 是脚本超过多长时间 就可以记录到日志文件
slowlog 是日志文件的路径

开启后,如果有脚本执行超过指定的时间,就会在指定的日志文件中写入类似如下的信息:


[19-Dec-2013 16:54:49] [pool www] pid 18575
script_filename = /home/web/htdocs/sandbox_canglong/test/tt.php
[0x0000000003a00dc8] curl_exec() /home/web/htdocs/sandbox_canglong/test/tt.php:2
[0x0000000003a00cd0] exfilter_curl_get() /home/web/htdocs/sandbox_canglong/test/tt.php:6
日志说明:
script_filename 是入口文件
curl_exec() : 说明是执行这个方法的时候超过执行时间的。
exfilter_curl_get() :说明调用curl_exec()的方法是exfilter_curl_get() 。
每行冒号后面的数字是行号。

开启后,在错误日志文件中也有相关记录。如下:





参考:http://www.bo56.com/%E5%96%84%E7%94%A8php-fpm%E7%9A%84%E6%85%A2%E6%89%A7%E8%A1%8C%E6%97%A5%E5%BF%97slow-log%EF%BC%8C%E5%88%86%E6%9E%90php%E6%80%A7%E8%83%BD%E9%97%AE%E9%A2%98/
背景: 深入理解PHP原理之变量分离/引用(Variables Separation)   之自己+1,这个refcount是否+1的问题。
Q:
有时候会在原有数值的基础上改变吧 比如$var++
A:两种情况,那个对象就不测试了:
情况1,字符:


---------- 调试PHP ----------
string(5) "jackX" refcount(2)
string(5) "jackY" refcount(2)

输出完成 (耗时 0 秒) - 正常终止


情况2,整数:


---------- 调试PHP ----------
long(1) refcount(2)
long(2) refcount(2)

输出完成 (耗时 0 秒) - 正常终止

说明,$var++; 并没有改变自己的refcount值。而像:$var_dup = $var;就会+1了哟:



---------- 调试PHP ----------
string(5) "jackX" refcount(2)
string(5) "jackY" refcount(3)  <---看,这儿+1,等于3了,$var_dup = $var;会加1,得证。

输出完成 (耗时 0 秒) - 正常终止
实践来源:http://www.laruence.com/2008/09/19/520.html


疑问:


---------- 调试PHP ----------
string(8) "laruence" refcount(3)
string(8) "laruence" refcount(3)
long(1) refcount(2)
string(8) "laruence" refcount(2)

输出完成 (耗时 0 秒) - 正常终止

可能是:
作为函数的参数穿进去的时候,函数的实参使用了,所以+1,函数电用完,实参也回收了,所以变回2,应该是这样,实践如下:

---------- 调试PHP ----------
string(9) "jackxiang" refcount(2)
string(9) "jackxiang" refcount(2)
string(9) "jackxiang" refcount(2)

输出完成 (耗时 0 秒) - 正常终止

运行debug_zval_dump后不是又变回去了?按这样说,那前面的结论都TM错了,$var ++,其refcount也是加了1的。这就是结论。要看是这么玩的,得看PHP这块的源代码。

背景:在拿代码量算KPI...跟程序员来这一套。--西乔漫画。IT部门谈到:马上部署代码覆盖测试,PHP这块有查了一下还真有类似的工具。
Web端PHP代码函数覆盖率测试解决方案:
主要是结合xdebug和Spike PHPCoverage这两个工具进行统计:
原创网址:http://blog.csdn.net/httpnet/article/details/1707377
辅助参考:
http://www.cnblogs.com/xuning/archive/2015/11/09/4950110.html
http://blog.jobbole.com/97236/
废话不多说,打开控制台,install package

搜 sublimelinter

先安装sublimelinter本体

安装完以后再搜索一下,安装sublimelinter-php

接下来,打开preferences-package settings-sublimeLinter-settings--user

如下配置:

{
    "user": {
        
        "linters": {
            
        },
        
        "paths": {
            "linux": [],
            "osx": [],
            "windows": [
                "D:\\xampp\\php"
            ]
        },
        
    }
}







就是添加一下 paths的参数值,指定一下你本地php目录。


然后关闭sublime,再次打开一个php脚本,试试吧。

有错误的地方在行号上会有红点提示在代码上会有红色方框,鼠标放红色方框上,错误信息在编辑器底部状态栏显示。

来自:http://my.oschina.net/cxz001/blog/204592
我的是独立出来的放在:/usr/local/php/etc/php.d/opcache.ini

opcache.enable_cli=0
opcache.enable=0

/bin/systemctl restart  php-fpm.service
访问后再修改为1像上面这样restart一下即可。

打开页面看到如下错误:“PHP is apparently set up to strip inline doc blocks. This will make several core apps inaccessible.”这可能是由缓存/加速器造成的,例如 Zend OPcache 或 eAccelerator。打开你的打开php.ini文件,找到:[opcache],设置为:opcache.enable=0 和 opcache.enable_cli=0。

[opcache]
opcache.enable=0
opcache.enable_cli=0  

[root@iZ25dcp92ckZ etc]# php -v
PHP 5.6.20 (cli) (built: Jul 11 2016 11:15:33)
Copyright (c) 1997-2016 The PHP Group
Zend Engine v2.6.0, Copyright (c) 1998-2016 Zend Technologies
    with Zend OPcache v7.0.4-dev, Copyright (c) 1999-2015, by Zend Technologies
    with Zend Guard Loader v3.3, Copyright (c) 1998-2014, by Zend Technologies

还没生效?
[root@iZ25dcp92ckZ php.d]# php -i|grep opcache

Additional .ini files parsed => /usr/local/php/etc/php.d/opcache.ini

找到:
/usr/local/php/etc/php.d/opcache.ini

[opcache]
zend_extension=/usr/local/php/ext/opcache.so
opcache.enable=0
opcache.memory_consumption=128
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=4000
opcache.revalidate_freq=60
opcache.save_comments=0
opcache.fast_shutdown=1
opcache.enable_cli=0
;opcache.optimization_level=0                  


[root@iZ25dcp92ckZ php.d]# service php-fpm restart
Gracefully shutting down php-fpm . done
Starting php-fpm  done
背景:redis这个新产品在sns时很火,而memcache早就存在, 但redis提供出来的功能,好多网站均把它当memcache使用,这是大才小用,这儿有30个方法来使用redis,值得了解。
这篇文章主要介绍了30个php操作redis常用方法代码例子,本文其实不止30个方法,可以操作string类型、list类型和set类型的数据,需要的朋友可以参考下
redis的操作很多的,以前看到一个比较全的博客,但是现在找不到了。查个东西搜半天,下面整理一下php处理redis的例子,个人觉得常用一些例子。下面的例子都是基于php-redis这个扩展的。
1,connect
描述:实例连接到一个Redis.
参数:host: string,port: int
返回值:BOOL 成功返回:TRUE;失败返回:FALSE
示例:

<?php  
$redis = new redis();  
$result = $redis->connect('127.0.0.1', 6379);  
var_dump($result); //结果:bool(true)  
?>  
2,set
描述:设置key和value的值
参数:Key Value
返回值:BOOL 成功返回:TRUE;失败返回:FALSE
示例:

<?php  
$redis = new redis();  
$redis->connect('127.0.0.1', 6379);  
$result = $redis->set('test',"11111111111");  
var_dump($result);    //结果:bool(true)  
?>  
3,get
描述:获取有关指定键的值
参数:key
返回值:string或BOOL 如果键不存在,则返回 FALSE。否则,返回指定键对应的value值。
范例:

<?php  
$redis = new redis();  
$redis->connect('127.0.0.1', 6379);  
$result = $redis->get('test');  
var_dump($result);   //结果:string(11) "11111111111"  
?>  
4,delete

描述:删除指定的键
参数:一个键,或不确定数目的参数,每一个关键的数组:key1 key2 key3 … keyN
返回值:删除的项数
范例:

<?php  
$redis = new redis();  
$redis->connect('127.0.0.1', 6379);  
$redis->set('test',"1111111111111");  
echo $redis->get('test');   //结果:1111111111111  
$redis->delete('test');  
var_dump($redis->get('test'));  //结果:bool(false)  
?>  
5,setnx
描述:如果在数据库中不存在该键,设置关键值参数
参数:key value
返回值:BOOL 成功返回:TRUE;失败返回:FALSE
范例:

<?php  
$redis = new redis();  
$redis->connect('127.0.0.1', 6379);  
$redis->set('test',"1111111111111");  
$redis->setnx('test',"22222222");  
echo $redis->get('test');  //结果:1111111111111  
$redis->delete('test');  
$redis->setnx('test',"22222222");  
echo $redis->get('test');  //结果:22222222  
?>  
6,exists
描述:验证指定的键是否存在
参数key
返回值:Bool 成功返回:TRUE;失败返回:FALSE
范例:

<?php  
$redis = new redis();  
$redis->connect('127.0.0.1', 6379);  
$redis->set('test',"1111111111111");  
var_dump($redis->exists('test'));  //结果:bool(true)  
?>  
7,incr
描述:数字递增存储键值键.
参数:key value:将被添加到键的值
返回值:INT the new value
实例:

<?php  
$redis = new redis();  
$redis->connect('127.0.0.1', 6379);  
$redis->set('test',"123");  
var_dump($redis->incr("test"));  //结果:int(124)  
var_dump($redis->incr("test"));  //结果:int(125)  
?>
  
8,decr
描述:数字递减存储键值。
参数:key value:将被添加到键的值
返回值:INT the new value
实例:

<?php  
$redis = new redis();  
$redis->connect('127.0.0.1', 6379);  
$redis->set('test',"123");  
var_dump($redis->decr("test"));  //结果:int(122)  
var_dump($redis->decr("test"));  //结果:int(121)  
?>
9,getMultiple
描述:取得所有指定键的值。如果一个或多个键不存在,该数组中该键的值为假
参数:其中包含键值的列表数组
返回值:返回包含所有键的值的数组
实例:

<?php  
$redis = new redis();  
$redis->connect('127.0.0.1', 6379);  
$redis->set('test1',"1");  
$redis->set('test2',"2");  
$result = $redis->getMultiple(array('test1','test2'));  
print_r($result);   //结果:Array ( [0] => 1 [1] => 2 )  
?>

10,lpush
描述:由列表头部添加字符串值。如果不存在该键则创建该列表。如果该键存在,而且不是一个列表,返回FALSE。
参数:key,value
返回值:成功返回数组长度,失败false
实例:

<?php  
$redis = new redis();  
$redis->connect('127.0.0.1', 6379);  
$redis->delete('test');  
var_dump($redis->lpush("test","111"));   //结果:int(1)  
var_dump($redis->lpush("test","222"));   //结果:int(2)  
?>

11,rpush
描述:由列表尾部添加字符串值。如果不存在该键则创建该列表。如果该键存在,而且不是一个列表,返回FALSE。
参数:key,value
返回值:成功返回数组长度,失败false
范例:

<?php  
$redis = new redis();  
$redis->connect('127.0.0.1', 6379);  
$redis->delete('test');  
var_dump($redis->lpush("test","111"));   //结果:int(1)  
var_dump($redis->lpush("test","222"));   //结果:int(2)  
var_dump($redis->rpush("test","333"));   //结果:int(3)  
var_dump($redis->rpush("test","444"));   //结果:int(4)  
?>

12,lpop
描述:返回和移除列表的第一个元素
参数:key
返回值:成功返回第一个元素的值 ,失败返回false
范例:

<?php  
$redis = new redis();  
$redis->connect('127.0.0.1', 6379);  
$redis->delete('test');  
$redis->lpush("test","111");  
$redis->lpush("test","222");  
$redis->rpush("test","333");  
$redis->rpush("test","444");  
var_dump($redis->lpop("test"));  //结果:string(3) "222"  
?>

13,lsize,llen
描述:返回的列表的长度。如果列表不存在或为空,该命令返回0。如果该键不是列表,该命令返回FALSE。
参数:Key
返回值:成功返回数组长度,失败false
范例:

<?php  
$redis = new redis();  
$redis->connect('127.0.0.1', 6379);  
$redis->delete('test');  
$redis->lpush("test","111");  
$redis->lpush("test","222");  
$redis->rpush("test","333");  
$redis->rpush("test","444");  
var_dump($redis->lsize("test"));  //结果:int(4)  
?>

14,lget
描述:返回指定键存储在列表中指定的元素。 0第一个元素,1第二个… -1最后一个元素,-2的倒数第二…错误的索引或键不指向列表则返回FALSE。
参数:key index
返回值:成功返回指定元素的值,失败false
范例:

<?php  
$redis = new redis();  
$redis->connect('127.0.0.1', 6379);  
$redis->delete('test');  
$redis->lpush("test","111");  
$redis->lpush("test","222");  
$redis->rpush("test","333");  
$redis->rpush("test","444");  
var_dump($redis->lget("test",3));  //结果:string(3) "444"  
?>

15,lset
描述:为列表指定的索引赋新的值,若不存在该索引返回false.
参数:key index value
返回值:成功返回true,失败false
范例:

<?php  
$redis = new redis();  
$redis->connect('127.0.0.1', 6379);  
$redis->delete('test');  
$redis->lpush("test","111");  
$redis->lpush("test","222");  
var_dump($redis->lget("test",1));  //结果:string(3) "111"  
var_dump($redis->lset("test",1,"333"));  //结果:bool(true)  
var_dump($redis->lget("test",1));  //结果:string(3) "333"  
?>

16,lgetrange
描述:
返回在该区域中的指定键列表中开始到结束存储的指定元素,lGetRange(key, start, end)。0第一个元素,1第二个元素… -1最后一个元素,-2的倒数第二…
参数:key start end
返回值:成功返回查找的值,失败false
范例:

<?php  
$redis = new redis();  
$redis->connect('127.0.0.1', 6379);  
$redis->delete('test');  
$redis->lpush("test","111");  
$redis->lpush("test","222");  
print_r($redis->lgetrange("test",0,-1));  //结果:Array ( [0] => 222 [1] => 111 )  
?>

17,lremove
描述:从列表中从头部开始移除count个匹配的值。如果count为零,所有匹配的元素都被删除。如果count是负数,内容从尾部开始删除。
参数:key count value
返回值:成功返回删除的个数,失败false
范例:

<?php  
$redis = new redis();  
$redis->connect('127.0.0.1', 6379);  
$redis->delete('test');  
$redis->lpush('test','a');  
$redis->lpush('test','b');  
$redis->lpush('test','c');  
$redis->rpush('test','a');  
print_r($redis->lgetrange('test', 0, -1)); //结果:Array ( [0] => c [1] => b [2] => a [3] => a )  
var_dump($redis->lremove('test','a',2));   //结果:int(2)  
print_r($redis->lgetrange('test', 0, -1)); //结果:Array ( [0] => c [1] => b )  
?>

18,sadd
描述:为一个Key添加一个值。如果这个值已经在这个Key中,则返回FALSE。
参数:key value
返回值:成功返回true,失败false
范例:

<?php  
$redis = new redis();  
$redis->connect('127.0.0.1', 6379);  
$redis->delete('test');  
var_dump($redis->sadd('test','111'));   //结果:bool(true)  
var_dump($redis->sadd('test','333'));   //结果:bool(true)  
print_r($redis->sort('test')); //结果:Array ( [0] => 111 [1] => 333 )  
?>

19,sremove
描述:删除Key中指定的value值
参数:key member
返回值:true or false
范例:

<?php  
$redis = new redis();  
$redis->connect('127.0.0.1', 6379);  
$redis->delete('test');  
$redis->sadd('test','111');  
$redis->sadd('test','333');  
$redis->sremove('test','111');  
print_r($redis->sort('test'));    //结果:Array ( [0] => 333 )  
?>

20,smove
描述:将Key1中的value移动到Key2中
参数:srcKey dstKey member
返回值:true or false
范例

<?php  
$redis = new redis();  
$redis->connect('127.0.0.1', 6379);  
$redis->delete('test');  
$redis->delete('test1');  
$redis->sadd('test','111');  
$redis->sadd('test','333');  
$redis->sadd('test1','222');  
$redis->sadd('test1','444');  
$redis->smove('test',"test1",'111');  
print_r($redis->sort('test1'));    //结果:Array ( [0] => 111 [1] => 222 [2] => 444 )  
?>

21,scontains
描述:检查集合中是否存在指定的值。
参数:key value
返回值:true or false
范例:

<?php  
$redis = new redis();  
$redis->connect('127.0.0.1', 6379);  
$redis->delete('test');  
$redis->sadd('test','111');  
$redis->sadd('test','112');  
$redis->sadd('test','113');  
var_dump($redis->scontains('test', '111')); //结果:bool(true)  
?>

22,ssize
描述:返回集合中存储值的数量
参数:key
返回值:成功返回数组个数,失败0
范例:

<?php  
$redis = new redis();  
$redis->connect('127.0.0.1', 6379);  
$redis->delete('test');  
$redis->sadd('test','111');  
$redis->sadd('test','112');  
echo $redis->ssize('test');   //结果:2  
?>
  
23,spop
描述:随机移除并返回key中的一个值
参数:key
返回值:成功返回删除的值,失败false
范例:

<?php  
$redis = new redis();  
$redis->connect('127.0.0.1', 6379);  
$redis->delete('test');  
$redis->sadd("test","111");  
$redis->sadd("test","222");  
$redis->sadd("test","333");  
var_dump($redis->spop("test"));  //结果:string(3) "333"  
?>

24,sinter
描述:返回一个所有指定键的交集。如果只指定一个键,那么这个命令生成这个集合的成员。如果不存在某个键,则返回FALSE。
参数:key1, key2, keyN
返回值:成功返回数组交集,失败false
范例:

<?php  
$redis = new redis();  
$redis->connect('127.0.0.1', 6379);  
$redis->delete('test');  
$redis->sadd("test","111");  
$redis->sadd("test","222");  
$redis->sadd("test","333");  
$redis->sadd("test1","111");  
$redis->sadd("test1","444");  
var_dump($redis->sinter("test","test1"));  //结果:array(1) { [0]=> string(3) "111" }  
?>

25,sinterstore
描述:执行sInter命令并把结果储存到新建的变量中。
参数:
Key: dstkey, the key to store the diff into.
Keys: key1, key2… keyN. key1..keyN are intersected as in sInter.
返回值:成功返回,交集的个数,失败false
范例:

<?php  
$redis = new redis();  
$redis->connect('127.0.0.1', 6379);  
$redis->delete('test');  
$redis->sadd("test","111");  
$redis->sadd("test","222");  
$redis->sadd("test","333");  
$redis->sadd("test1","111");  
$redis->sadd("test1","444");  
var_dump($redis->sinterstore('new',"test","test1"));  //结果:int(1)  
var_dump($redis->smembers('new'));  //结果:array(1) { [0]=> string(3) "111" }  
?>

26,sunion
描述:
返回一个所有指定键的并集
参数:
Keys: key1, key2, … , keyN
返回值:成功返回合并后的集,失败false
范例:

<?php  
$redis = new redis();  
$redis->connect('127.0.0.1', 6379);  
$redis->delete('test');  
$redis->sadd("test","111");  
$redis->sadd("test","222");  
$redis->sadd("test","333");  
$redis->sadd("test1","111");  
$redis->sadd("test1","444");  
print_r($redis->sunion("test","test1"));  //结果:Array ( [0] => 111 [1] => 222 [2] => 333 [3] => 444 )  
?>

27,sunionstore
描述:执行sunion命令并把结果储存到新建的变量中。
参数:
Key: dstkey, the key to store the diff into.
Keys: key1, key2… keyN. key1..keyN are intersected as in sInter.
返回值:成功返回,交集的个数,失败false
范例:

<?php  
$redis = new redis();  
$redis->connect('127.0.0.1', 6379);  
$redis->delete('test');  
$redis->sadd("test","111");  
$redis->sadd("test","222");  
$redis->sadd("test","333");  
$redis->sadd("test1","111");  
$redis->sadd("test1","444");  
var_dump($redis->sinterstore('new',"test","test1"));  //结果:int(4)  
print_r($redis->smembers('new'));  //结果:Array ( [0] => 111 [1] => 222 [2] => 333 [3] => 444 )
?>

28,sdiff
描述:返回第一个集合中存在并在其他所有集合中不存在的结果
参数:Keys: key1, key2, … , keyN: Any number of keys corresponding to sets in redis.
返回值:成功返回数组,失败false
范例:

<?php  
$redis = new redis();  
$redis->connect('127.0.0.1', 6379);  
$redis->delete('test');  
$redis->sadd("test","111");  
$redis->sadd("test","222");  
$redis->sadd("test","333");  
$redis->sadd("test1","111");  
$redis->sadd("test1","444");  
print_r($redis->sdiff("test","test1"));  //结果:Array ( [0] => 222 [1] => 333 )  
?>
  
29,sdiffstore
描述:执行sdiff命令并把结果储存到新建的变量中。
参数:
Key: dstkey, the key to store the diff into.
Keys: key1, key2, … , keyN: Any number of keys corresponding to sets in redis
返回值:成功返回数字,失败false
范例:

<?php  
$redis = new redis();  
$redis->connect('127.0.0.1', 6379);  
$redis->delete('test');  
$redis->sadd("test","111");  
$redis->sadd("test","222");  
$redis->sadd("test","333");  
$redis->sadd("test1","111");  
$redis->sadd("test1","444");  
var_dump($redis->sdiffstore('new',"test","test1"));  //结果:int(2)  
print_r($redis->smembers('new'));  //结果:Array ( [0] => 222 [1] => 333 )  
?>

30,smembers, sgetmembers
描述:
返回集合的内容
参数:Key: key
返回值:An array of elements, the contents of the set.
范例:

<?php  
$redis = new redis();  
$redis->connect('127.0.0.1', 6379);  
$redis->delete('test');  
$redis->sadd("test","111");  
$redis->sadd("test","222");  
print_r($redis->smembers('test'));  //结果:Array ( [0] => 111 [1] => 222 )  
?>
  
php-redis当中,有很多不同名字,但是功能一样的函数,例如:lrem和lremove,这里就不例举


来自:http://m.jb51.net/article/51884.htm
背景:在本人用PHP和硬件进行交互的时候,用过dio_open这些,但硬件有硬件的特点,特别是一些位啥的,这儿就有一个问题涉及到串口16进制啥的,这位兄弟在实践中遇到的一些转化如:chr()、hexdec()、bin2hex()这3个函数,网上还提到了用pack()、unpack(),因为前面3个函数以及很好的解决了问题,所以就没有继续深入。 再就是用fiddler来看发送的十六进制,以及在进行十六进制转十进制的一些问题,很有价值:
一)转换函数:


二)再谈fiddler2的一个好处:
优雅的快速测试
由于PHP是弱类型,因此理解起来比较费解。接收数据和向硬件发送数据的数据类型是不一样的。用bin2hex()得到的是形如"11 00 00 FE"的字符串,用chr(hexdec())得到的是16进制的ASCII码,如果echo输出的话,会是乱码。那么如何测试(看到)自己生成的16进制ASCII码数据是否正确呢?1种是找一个TCP/IP工具发送过去,这种麻烦了点,我推荐用fiddler监听。


HexView中的黑色部分就是你发送的
你可以快速方便的用一个web页面输出你的ASCII码,在fiddler的HexView中,就可以看到原汁原味你发送的16进制数据了。另外,由于Swoole的监听类是CLI运行,因此我也非常推荐多写一点echo打印一下状态,在phpstorm的SSH客户端里可以快速的了解目前的情况,就像android-studio的Loger一样。

三)echo Carbon::now() . '/Device Numbers:' . $devNum . PHP_EOL;//老司机劝你多写点,最好packagist找个轮子或者自己写个Logger库


除开本人的一个眉批外,以上摘录自:
文/保安保安(简书作者)
原文链接:http://www.jianshu.com/p/b25e8b46bd02
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。

背景:对于死锁的问题,人们往往想到出现一些关于访问很缓慢,有白页现象,要是测试环境(我就真实遇到测试环境有本文谈及一样的问题)你也就重启一下PHP的php-fpm进程发现又好了,隔一段时间又出类似的问题,你会看下日志,你会发现有很多日志是“Max execution timeout of 60 seconds exceeded”,你会发现这可能是一些php的守护进程导致的,你为了解决测试环境的问题,于是觉得应该把那个php-fpm的进程数开多点,可能会好一些,于是你开多了,一直没有面对这个问题的原因,为什么呢,因为公司装PHP的是运维装的,你没有办法或时间去装一个debug版本的php,你说这个问题让运维的人来查,你觉得能查出来?So,这个问题一拖再拖,但就是没解决,但是有一天你发现磁盘满了,用du去看整体时发现满了,但是如果一个个目录去看发现并没有占用多少,也万万没有想到PHP的死锁还会导致磁盘空间占用太多,上面这种情况我就真实遇到过,后来重新reboot操作系统,磁盘又回来了,所以,我认为是一篇好文章,所以转了此文,也想说明对于PHP的扩展这方面代码质量把关需要严格,再就是PHP本身关于锁这块要弱化(除开cookie/session和cache锁外,其它能不用就不用),尽可能少用锁,这是博主一点小看法,同时把那些比如发短信啥的能异步的给用swoole异步了(这儿有点广告嫌疑),解放出php-fpm进程,防止因为阻塞导致hold住了PHP的php-fpm进程,像php下面的队列demon这种,能单独放就单独放一台机器隔离开,减少出现错误和问题的各种猜忌影响判断,下面言归正传。


引子:
本期我们邀请到了 云盘服务端 团队的技术达人- 徐铁成,一个隐蔽已久的PHP死锁问题被层层掘出,感谢铁成为我们带来这次畅快的体验,小伙伴们,准备好这次技术之旅了么?
---------------
发现问题
近期发现线上很多机器的磁盘空间报警, 且日志文件已经清理,但是磁盘空间没有释放。通过ps aux | grep php-cgi 发现, 很多进程的启动时间在几天到几周甚至几个月之前。我们线上的php-cgi都有最大执行次数的。一般在1天内都会重启一次。初步结论,这些cgi进程有问题。
通过lsof -p [pid] 发现, 启动时间很久的cgi进程中打开了一些日志文件句柄,并且没有关闭。这些日志文件在文件系统中已经删除了。但是句柄没关闭,导致磁盘空间没有释放。到此,磁盘空间异常的问题基本确定。是由于cgi没有关闭文件句柄造成的。
进一步分析进程, strace -p [pid], 发现所有异常的进程都阻塞与 fmutex 状态。换句话所,异常的cgi进程死锁了。进程死锁导致打开的文件句柄没有关闭,所以导致磁盘空间异常。

为什么cgi进程会死锁呢?

什么是死锁
学过操作系统的通同学,都了解多线程的概念。在多线程中访问公共资源,需要对资源加锁。访问结束后,释放锁。如果没有释放锁,那么下一个线程来获取资源的时候就会永远都无法获取资源的锁,于是这个线程死锁了。那么CGI是多线程的公共资源访问导致的死锁吗? 答案是NO。
1. CGI 是单线程进程,通过ps 就能看到。(进程状态 Sl的才是多线程进程)。
2. 即使是多线程的,死锁发生在PHP的shutdown过程中调用glibc 中time 函数的位置,不是php模块造成的。而glibc 中的time相关函数是线程安全的,不会产生死锁。

那是什么导致的死锁呢?
通过分析linux中死锁产生的机制,发现除了多线程会产生死锁外,信号处理函数同样会产生死锁。那么cgi是由于信号处理导致的死锁吗?在这之前介绍一个感念。

函数的可重入性与信号安全
函数可重入是指,无论第几次进入该函数,函数都能正常执行并返回结果。那么线程安全函数是可重入的吗?答案是NO。 线程安全函数,在第一次访问公共资源时,会获取全局锁。如果函数没有执行完成,锁还没释放,此时进程被中断。那么在中断处理函数中,再次访问该函数,就会产生死锁。那么什么样的函数才可以在中断处理函数中访问呢? 除了没有使用全局锁的函数,还有一些signal safe的系统调用可以使用。调用任何其他的非signal safe的函数都会产生不可预知的后果(比如 死锁)。 详见 man signal。在分析死锁的原因前,我们先看看cgi执行的流程,分析其中有没有产生死锁的可能。

PHP-CGI的执行流程
Glibc中的时间函数使用到了全局锁,保证函数的线程安全,但没有保证信号安全(signal safe)。经过之前的分析,我们初步怀疑死锁是由于PHP-CGI进程接收到了一个信号,然后在signal handle中执行了非signal safe的函数。主流程在中断前,正在执行glibc中的时间函数。在函数获取的锁没释放前,进入中断流程。而中断过程中又访问了glibc中的时间函数。于是导致了死锁。
PHP-CGI的执行流程,如下图所示:
点击在新窗口中浏览此图片
进一步分析发现,所有死锁的cgi进程的sapi_global中都记录了一个错误信息
“Max execution timeout of 60 seconds exceeded”.
60s 是我们php-cgi中设置执行超时。所以我们确认了,cig在执行过程中的确产生了超时异常,然后由于longjmp进入了shutdown过程。在shutdown过程中访问了glibc中的时间函数。导致了死锁。
void zend_set_timeout(long seconds)
{
TSRMLS_FETCH();

EG(timeout_seconds) = seconds;
if(!seconds) {
return;
}
……

setitimer(ITIMER_PROF, &t_r, NULL);
signal(SIGPROF, zend_timeout); // 此处会调用zend异常处理函数
sigemptyset(&sigset);
sigaddset(&sigset, SIGPROF);

……
}
通过gdb调试发现,所有PHP-CGI都阻塞在zend_request_shutdown中。zend_request_shutdown会调用用户自定义的php脚本中实现的shutdown函数。如果CGI执行超市,那么定时器会产生SIGPROF信号使执行流程中断。如果此时脚本刚好处于调用时间函数的状态,且还没有释放锁资源。然后执行流程进入了 timeout 函数,继续跳转到zend_request_shutdown。此时如果自定义的shutdown函数中访问了时间函数。就会产生死锁。我们从代码中找到了证据:
register_shutdown_function ('SimpleWebSvc:: shutdown’);
我们在php代码中使用qalarm系统,qalarm系统会在cgi执行结束(shutdown)的时候,注入一个钩子函数,来分析cgi执行是否正常,如果不正常,则发送报警信息。而刚好qalarm的报警处理函数中访问了时间函数。于是就有一定的概率产生死锁。

结论
通过上面的分析,我们找到了cgi死锁产生的原因,是应为在signal handler中使用了非signal safe的函数,导致了死锁。

解决办法
去掉或简化qalarm注册到shutdown中的钩子函数。避免不安全的函数调用。

来自:http://www.v2gg.com/lady/shishangzixun/20140924/57266.html
每天早上2-3小时shell论坛,今天终于把精华帖子恳完了,放点好脚本给各位,学shell上cu,没事逛逛论坛,心情好的时候看看精华贴.进步那真是飞一般的感觉.
不过新手最好还是先潜水一个月,在开始发帖回帖.最近论坛帖子质量严重下降都是1+1=?.
zj@zj:~/Script/cushell/08.11.04$ cat checkip.sh

解释下:
grep -Eq '[^0-9.]|^\.|\.$|^0*\.|\.\.'
[^0-9.]是不是有除了0-9与.之外的字符
^\.|\.$  以.开头 or 以.结尾
^0*\.|\.\. 以0开头 or 连续两个.
以上三种情况都是错误的哦,所以就printerr

echo -e "${IP//./\n}" | wc -l说实话前面那种替换我也是first time.就是讲.替换为换行,3个点就是4行了哦.不是3个点也就printerr

$((10#$i/8)) -gt 31 这个就是判断是不是<=255的了,当然你也可以自己修改成$i -gt 255

OK解释完毕^_^
zj@zj:~/Script/cushell/08.11.04$ ./checkip.sh 1.2.3.4
1.2.3.4 is
zj@zj:~/Script/cushell/08.11.04$ ./checkip.sh 01.2.3.4
incorrect IP format.
Your IP: a.b.a.d
incorrect IP format.
Your IP: 266.1.1.1
incorrect IP format.
Your IP: 244.255.255.255
244.255.255.255 is

来自:http://blog.chinaunix.net/uid-9950859-id-98351.html
更复杂的且更精确的判断:http://www.shangxueba.com/jingyan/1898546.html
Swoole在实际项目中的应用
[PHPer]Swoole在实际项目中的应用(不讲入门,只有实战)
2016年6月18日 13:30 ~ 2016年6月18日 17:00
(北京海淀)中关村海龙大厦办公楼17层(星巴克咖啡北侧办公大厅入口)
限额100人
本次活动由Swoole框架内核开发者王晶(网名半桶水,人称桶哥)发起,由优才学院、内聘网联合主办。
[活动对象]
本次活动针不讲入门只讲实战,我们希望你:
1、PHPer,一年以上
2、对Swoole了解或者应用过
3、对开源项目感兴趣,并持续关注开源项目

发起当天就有70多人参加,欢迎你的加入。


报名链接:
http://www.huodongxing.com/event/5337738177600

背景:我都之前说php7对wordpress提升不大,没有一个兄弟支持我,都说提升大,你看这文章,qq会员那边的一个实践更多证实了我的观点。

                                                                               ......
在benchmark(测试程序)中得到非常好的结果,实现JIT后性能比PHP5.5提升了8倍。然而,当他们把这个优化放入到实际的项目WordPress(一个开源博客项目)中,却几乎看不见性能的提升。原因在于测试项目的代码量比较少,通过JIT产生的机器码也不大,而真实的WordPress项目生成的机器码太大,引起CPU缓存命中率下降(CPU Cache Miss)。
                                                                               ......

对apache的工作模式分析很透彻:
Prefork、Worker、Event三者粗略介绍:

(1)prefork,多进程模式,1个进程服务于1个用户请求,成本比较高。但是,稳定性最高,不需要支持线程安全。
(2)worker,多进程多线程模式,1个进程含有多个worker线程,1个worker线程服务于1个用户请求,因为线程更轻量,成本比较低。但是,在KeepAlive场景下,worker资源会被client占据,无法响应其他请求(空等待)。
(3)event,多进程多线程模式,1个进程也含有多个worker线程,1个worker线程服务于1个用户请求。但是,它解决了KeepAlive场景下的worker线程被占据问题,它通过专门的线程来管理这些KeepAlive连接,然后再分配“工作”给具体处理的worker,工作worker不会因为KeepAlive而导致空等待。

博文摘自 : http://geek.csdn.net/news/detail/77849
分页: 5/26 第一页 上页 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 下页 最后页 [ 显示模式: 摘要 | 列表 ]