php执行Linux命令的方法(具体案例)

最近本人在做一个系统用来管理团队的任务,其中涉及到我们的任务需要选择项目的git分支,我的方案是利用php去获取某个项目的远程仓库的分支:
exec(“cd /data/www/superb/Git/saint;git pull;git branch -r”, $output);
解释下:
cd /data/www/superb/Git/saint # 跳到从git项目拉下来的代码目录下
git pull  # 更新代码
git branch -r  # 获取当前代码目录下本地和远程所有的代码
一句话执行以上三句需要加上分号。
后来发现git pull无效的问题,即服务器的代码目录并没有自动更新,我获取的远程分支不是最新的。后来发现原来是没有权限,因为git pull这种的写操作无法执行,而git branch这样的读操作是可以执行的。
我的服务器是nginx+php-fpm,最终执行这个linux shell命令的用户是php-fpm的www,使用ps aux | grep php-fpm查看,而且我用php exec执行了whoami:
exec(“whoami”, $output);
也证明了用户是www,于是我将www用户添加到了服务器的sudo列表里:
vim /etc/sudoers
增加一行:
www             ALL=(ALL)       NOPASSWD:ALL
# www             ALL=(ALL)       ALL
下面一行注释掉的和第一行的区别是第一行的配置当www用户在执行sudo操作的时候不需要密码,第二行的配置是所有的sudo操作都要输入www用户的密码。
我把php的代码改成了:
exec(“cd /data/www/superb/Git/saint;sudo git pull;git branch -r”, $output); // git pull用sudo来执行
结果发现依然没有效果,最后我只好用下下策,将/data/www/superb/Git/saint目录和子目录文件的用户和组改为了www:
chown -R www:www  /data/www/superb/Git/saint/
最终php的命令改为:
exec(“cd /data/www/superb/Git/saint;git pull;git branch -r”, $output); // 把sudo去掉
这样就可以执行了,最终实现了我的目标。

php过滤 的方法

今天我在处理一些数据的时候,看到页面上的字符串前面有空格,就用了trim()想要过滤掉字符串前面的空格,但是存入数据库之后字符串的前面依然有空格,查看了页面的源代码之后才发现字符串的前面是 ,然后直接使用:

str_replace(' ', '', $str);

来替换 结果发现根本没有被替换掉。

尝试使用ASCII码来匹配:

str_replace(chr(0xC2) . chr(0xA0), '', $str);

最后 终于被替换掉了!

dedecms后台无法登录解决办法

今天开始修改一个基于dedecms的网站,我要登录它的后台管理系统,地址是domain/dede,页面显示正常,用户名和密码输入没有问题,结果显示一片空白,根本无法进入后台,于是我开始查找问题所在。

我先找到到dede下的login.php,经过我各种断点之后,发现是79行的:

$cuserLogin->keepUser();

有问题,$cuserLogin是userLogin类的对象,userLogin类的位置在dedecms的include中的userlogin.class.php,在290行左右有一句:

@session_register($this->keepUserIDTag);

我去掉了代码前面的@,程序的报错终于出来了,我到php的手册里查了下session_register这个方法,里面写着大大的Warning:

Warning

本函数已自 PHP 5.3.0 起废弃并将自 PHP 5.4.0 起移除

好了!原来如此!我的php正好是5.4,这可如何是好啊?要不我重写一个session_register方法吧!

function session_register(){
	$args = func_get_args();
	foreach ($args as $key){
		$_SESSION[$key]=$GLOBALS[$key];
	}
}

将这段代码写入userlogin.class.php中,dedecms的后台就成功登录进去了!不知道dedecms官方啥时候修改这个bug啊?

PHP使用array_slice之后数组的键被改变的解决方法

今天遇到一个问题,用股票代码作为key的数组在array_slice之后6开头的键值会变成0和1:
array_slice($totalResult, 0, 5);
Array
(
    [000950] => 78.6982
    [000960] => 76.982
    [0] => 76.8926
    [002541] => 76.7676
    [1] => 76.2656
)
在array_slice后面加上第四个参数true之后就正确了:
array_slice($totalResult, 0, 5, true);
Array
(
    [000950] => 78.6982
    [000960] => 76.982
    [600259] => 76.8926
    [002541] => 76.7676
    [600765] => 76.2656
)
array array_slice ( array $array , int $offset [, int $length = NULL [, bool $preserve_keys = false ]] )
的解释:
preserve_keys
注意 array_slice() 默认会重新排序并重置数组的数字索引。你可以通过将 preserve_keys 设为 TRUE 来改变此行为。

使用单例模式解决PHP耗尽服务器内存的问题

今天公司的项目出现了php超过了服务器内存限制的错误:
PHP Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 1792 bytes) in *****
后来发现Alert_Push_Main类中的main()是一个死循环观察者,一直在调用atom(),而atom()中的观察者类Alert_Push_Observer将一直被new即分配内存,我使用memory_get_usage()看了下内存的使用情况,每运行一次atom()会消耗1088bytes的内存,而这个main()是一个死循环,进程一直没有停止,导致这些内存没有释放掉,最终铸成了服务器内存耗尽的问题。
<?php
class Dzl_Alert_Push_Main
{
     public static function main()
     {
          while (true) {
               $weekday = date('w', strtotime(date('Y-m-d')));
               if (date('H:i:s') <= '15:00:00' 
               && date('H:i:s') >= '09:25:00'
               && $weekday != 0 && $weekday != 6) {
                    self::atom();
               } else {
                    //用于停掉观察者的死循环
                    break;
               }
          }
     }

     public static function atom()
     {
          $one = new Dzl_Alert_Push_Subject_Main();
          //下面这句是罪魁祸首!!!
          $observer = new Dzl_Alert_Push_Observer($one);
          $one->dealTrigger();
     }
}
解决方法:
这个时候我想到了单例模式,进程中只要一个Alert_Push_Observer对象就可以了:
<?php
class Dzl_Alert_Push_Main
{
     public static function main()
     {
          while (true) {
               $weekday = date('w', strtotime(date('Y-m-d')));
               if (date('H:i:s') <= '15:00:00' 
               && date('H:i:s') >= '09:25:00'
               && $weekday != 0 && $weekday != 6) {
                    self::atom();
               } else {
                    //用于停掉观察者的死循环
                    break;
               }
          }
     }

     public static function atom()
     {
          $one = new Dzl_Alert_Push_Subject_Main();
          //将下面这句改成了单例模式
          $observer = Dzl_Alert_Push_Observer::getInstance()->setSubject($one);
          $one->dealTrigger();
     }
}