PHP 浏览器关闭 和timeout之后,php程序还会执行吗?

13 Dec 2015 Category: PHP

在 PHP 内部,系统维护着连接状态,其状态有三种可能的情况: 0 - NORMAL(正常) 1 - ABORTED(异常退出) 2 - TIMEOUT(超时) 当 PHP 脚本正常地运行 NORMAL 状态时,连接为有效。当远程客户端中断连接时,ABORTED 状态的标记将会被打开。当连接时间超过 PHP 的时限时,TIMEOUT 状态的标记将被打开。


<?php
set_time_limit(60);
$interval = 5;
do {

    $fp = fopen('text3.txt', 'a');

    fwrite($fp, "test\n\r");

    fclose($fp);

    sleep($interval); // 函数延迟代码执行若干秒

} while (true);

?>

对于上述代码,如果我一打开就立刻关掉该页面,应该会在文件里写多少次test呢?事实证明, 当服务器ignore_user_abort开启的时候,执行12次,就是说,即时用户关掉了 浏览器,PHP脚本也会只执行完,除非遇到timeout的情况。 当ignore_user_abort关闭的时候,会随着用户的终端而终端脚本

注意,面对这种情况,必须确认服务器ignore_user_abort的设置是有效的,xampp似乎无效

查看更多

SSO 登陆简单实现

11 Dec 2015 Category: PHP

SSO又称单点登录。简单的说就是多个站点应用(域名不一定在同一个主域名下),在任意一 个子系统中登录,其他系统都实现登陆。同样,一个站点退出,其他站点也退出。

SSO 登录的难点在于如何保持多个系统同步。

实现SSO登陆的步骤如下:

  • 子系统点击登陆,带上redirect作为返回路径跳转到sso统一登录页面(passport)进行 登录。

  • 用户在passport登录之后(写入passport的session,cookie等登录信息),通过js向各个 子系统的登录接口(并带上passport的临时票据ticket)

  • 子系统的登录接口中,确定请求的合法性,并根据请求的临时票据ticket请求passport服务器获 取用户信息(这里是服务器跟服务器直接通讯,因此passport需要能够根据ticket获取到用户信息), 并将用户信息写入登陆状态中,登录用户,写子系统的session,cookie

  • 所有子系统写完之后,根据一开始请求passport的跳转参数redirect进行跳转条主, 回到登录前的子系统

退出过程:

  • 子系统点击退出,跳转到passport的退出操作,并生存退出票据ticket

  • passport退出页面中可通过ajax请求各个子系统

  • 各个子系统判断ticket的合法性,退出用户

上面的就是整个sso的过程,其实这里面还有一些方面没处理。所有的登录登出操作都是在 passport处理的,因此数据同步是单项性的。如果各个登录登出操作是在每个子系统本身处 理的,那就需考虑client到passport的状态同步。同时,单点登录系统需要对参数进行加密, 子系统和passport直接可以根据同样的key对参数进行ras加密,保证数据传输过程中不被破解

个人代码可参见github

查看更多

Yii2 CMS 系统 DanDan CMS开发基本完成

27 Nov 2015 Category: PHP

最近几天,忙于完成DanDan CMS,博客更新速度有些慢。今天基本完成。DanDan CMS系统源码 https://github.com/froyot/dandan

DanDan CMS系统采用YII2 basic版本进行开发,实现多模块,多主题,内容发布等基础功能。 整个系统写下来,还是需要考虑很多东西,各个模块之间的联系,代码的统筹,结构划分等 都是一门学问

对于一个具有前台,后台的内容发布系统,model层如何划分?是先按业务划分还是按结构划 分呢?如果按结构,直接前后台模块分开,各自一个model,那么问题又来了,哪些是可以共用 的,哪些是需要区分的。如果按业务划分model\db下直接对接数据库,不做业务处理, model\action负责主要业务处理,不管前台后台,所有的操作都经过models\action进行。 我比较推崇这种处理方式,我觉得,一个model所具有的属性,操作是其本身所具有的,不会 因为其运用环境不同而不同,只是需要根据不同的环境应用不同的属性。但是这样也有问题, 后台常常因为运营需要,需要连接不同的表,但是前台则不需要。后台需要添加一些临时属性, 以便于数据的编辑,但前台不需要,这个时候就需要根据结构进行划分。

在写DanDan CMS系统的时候,刚开始,一切都不太清晰,这个时候比较凌乱,理不清头像。 但是这个时候的代码却是基础,如果这个时候基础设计不和里,等整个系统出来之后,就会 明显觉得当初结构设计是多么蹩脚,以至于束缚现有的开发。在DanDan CMS中就有这样的体会, 因此后期会进行很大的调整,但是所有的调整都是缓慢进行,不会一次性进行大的重构,保证 每次改变都是在整个体系清晰的情况下进行。

查看更多

Yii2 中使用registerJsFile引入asset发布的js文件

14 Nov 2015 Category: PHP

Yii2 提供AssetManage对一些不对外的目录的静态文件发布到可访问的asset目录中。如果 所有的静态文件都通过AssetBundle的方式进行引入,那倒没什么值得说的了。不过像js文 件,由于依赖关系,有时候不得不在文件开头就引入某个js文件,同时其他js文件依然在文 件底部加载。这个时候我们不得不在模板或者视图文件中使用registerJsFile对js文件进行 引入。

但是,在视图或者模板文件中,如果我们想直接引入web目录下的js文件直接采用别名@web 就可以,但是如果想要访问asset目录呢? 假设模板文件中,注册了AssetBundle $bundel, 采用下面的方式引入改AssetBundle 中发 布的asset 静态文件


<?php
    $manager = $this->getAssetManager();
    $url = $manager->getAssetUrl($bundel,'js/vue.min.js');
    $this->registerJsFile($url,['position'=>yii\web\View::POS_HEAD]);
?>

查看更多

SSH 防止暴力破解

10 Nov 2015 Category: Developer

最近看服务器日志,发现secure日志中有很多登录验证记录,估计是被盯上了。ssh暴力扫 描破解。ssh本身是几次密码错误之后就断开,但是还可以继续连接,然后再试密码和端口。 如果ssh扫描频率大,自己就会没办法连接到服务器,因为服务器一直在验证那些实验的密码。

在网上看到一个脚本,用来将多次密码错误尝试的ip拉进小黑屋。从此拒绝改ip的请求。

#!/bin/bash
#Denyhosts ssh error ip

cat /var/log/secure|awk '/Failed/{print $(NF-3)}'|sort|uniq -c|awk '{print $2"=" $1;}' >/root/bin/Denyhosts.txt
DEFINE="3"
for i in `cat /root/bin/Denyhosts.txt`
do
IP=`echo $i|awk -F= '{print $1}'`
NUM=`echo $i|awk -F= '{print $2}'`
if [ $NUM -gt $DEFINE ]
then
grep $IP /etc/hosts.deny >/dev/null
if [ $? -gt 0 ];
then
echo "sshd:$IP" >> /etc/hosts.deny
fi
fi
done

以上代码在不同的服务器需要适当修改。 在我的虚拟机里面,log里没有secure文件,登陆记录在auth.log里。 另外需要保证/root/bin/Denyhosts.txt文件存在。

存在一个问题,因为即使公司里很多都是使用动态ip的,万一哪天分配的ip跟黑名单里 面的ip一样,那就无力回天了。

查看更多

PHP POST 数组限制

07 Nov 2015 Category: PHP

今天调一个接口,测试批量上传数据。上传数据用的是POST方式,分成一个多维数组上传。 但是,问题来了,最多可以批量上传多少条数据?PHP默认POST数据的限制是2M,但是并不代 表你就可以真的传2M以内的任意长度的数组。

PHP对输入变量是有限制的。默认php.ini里的max_input_vars的限制是1000.如果POST一个二维数组,每个二维子数组里有五个元素,那么,只能POST200个子数组。那 么多余的整么办?直接抛掉。。。。。真是简单粗暴。那么抛掉的策略是怎么样的呢?比如我POST上述数组210个,另外还POST一个变量type,那么服务器的$_POST参数里有啥?

一下数据是通过PHP CURL方式提交的,其他语言提交之后数据顺序不一定不变

$data['ztype'] = "ztype";
$data['aber'] = "aber";
$data['User'] = [];
for($i=0;$i<290;$i++)
{
    $data['User'][] = [
        'create_time'=>1,
        'health_action_cat_id' => '5',
        'detail' => '{"distance":44}',
        'uid' => '5089',
        'provider_id'=>$i,
    ];
}

如果提交的数组是这样的,那么,服务器的$_POST是这样的:

{
    "ztype":"ztype",
    "aber":"aber",
    "User": [0-198]
}

那如果顺序变一下呢,

$data['User'] = [];
for($i=0;$i<290;$i++)
{
    $data['User'][] = [
        'create_time'=>1,
        'health_action_cat_id' => '5',
        'detail' => '{"distance":44}',
        'uid' => '5089',
        'provider_id'=>$i,
    ];
}
$data['ztype'] = "ztype";
$data['aber'] = "aber";

服务器的$_POST是这样的:

{
    "User": [0-199]
}

额,这个…难怪容易出现诡异的情况。像其他语言(比如java),提交之后数据顺序是不确定的,所以,所以就会出现数据混乱,在获得1000个变量之后,PHP将抛弃后面的输入。如果下一个数组大小加起来已经超过1000,PHP也会果断抛弃….

查看更多

Vue.js router 切换后执行某个操作

05 Nov 2015 Category: Developer

Vue.js 是一个MVVM前端框架,这几天拿来做自己的小东西,学习当中。遇到一个问题.当使用router的时候,如何在切换之后执行页面初始化的操作。其他想page.js的路由都 有callback之类的回调函数,但是vue-router好像没有。

于是在网上搜索了半天,终于有了一个稍微可行的方案。

vue-router注册的是一个个个的vue-component,在注册的时候可以配置一些属性。 vue-router提供的属性都是在页面被创建之前执行的,而很多时候,比如需要对一些页面 元素绑定某些类似于slider的插件,就必须在页面创建之后才能给通过 document.getElementById获得该元素。既然router文档中提供的配置属性没办法实现,那么vue-component本身呢。 stackoverflow里有提到过component的几个属性:

  • created:function(){},在这里面还是无法获取页面元素

  • attached:function(){},到这里才能获取!!!!

所以,可以把单纯的数据初始化放置在created里面,而把需要操作页面dom的放置在attached

查看更多

PHP 通过搜狗搜索 抓取微信公众号数据

04 Nov 2015 Category: Developer

微信公众号的文章抓取一直以来由于微信本身的封闭性抓取比较困难。好在现在搜狗搜索 可以搜索微信数据。因此用PHP进行实现数据的抓取。

PHP数据抓取的思路无非是curl请求然后正则匹配,然后获取数据。顶多再添加一个cookie, 处理301,302跳转。如果以上还是无法获取,那就说明,真是搞不定了。

造出这个轮子,有一下收获:

  • 首先现阶段,很多网页是通过前端模板进行渲染的,因此,如果想从页面中获取js渲染 之后的数据,那PHP是搞不定了,这就需要用node.js 的cheerio或其他js库进行处理。

  • curl中允许跳转,需要设置参数CURLOPT_FOLLOWLOCATION ,但是!!!!

Warning: curl_setopt() [function.curl-setopt]: CURLOPT_FOLLOWLOCATION cannot be activated when safe_mode is enabled or an open_basedir is set in /home/xxx/public_html/xxx.php on line 56

,所以不是每次都可以让你设置CURLOPT_FOLLOWLOCATION。如果不能设置这个值,就需要对 返回头进行判断,判断是否是301,或302,并获取跳转地址。可以设置CURLOPT_HEADER参数 为true,让请求头作为数据流返回,从返回中采用正则方式匹配跳转后的地址。对于返回 code的判断,则可以通过curl_getinfo($ch, CURLINFO_HTTP_CODE)获取。

  • 如果在header中添加一个Cookie头,同时,请求的时候添加了cookie文件,那么发出去 的请求中包含两个cookie的内容。

  • sleep函数在一些主机上,处于安全原因是不允许使用的!!!!

    

查看更多