crontab 里 % 引发的问题

最近在写一个crontab的时候发现的一个问题,这里记录一下
计划执行一个带cookie抓取页面内容的小任务,其中cookie里有一个百分号%,
然后 查看/var/log/cron 发现执行内容并不正确,翻看手册才发现在这样一句

Percent-signs (%) in the command, unless escaped with backslash (\), will be changed into newline characters, and all data after the first % will be sent to the command as standard input.

%如果没有用\转义就会被当做另外一行,不管是否有 引号 都会这样.

[翻译]在phpstorm中配置xdebug

这是一篇翻译文章,原文请见 配置Phpstorm,Xdebug

PhpStorm 和 XDebug 是非常帅气的一对搭档

大部分时候缺少一个debugger工具会导致你无法高效的编写代码,我为一个定制化的wordpress网站工作,通过debugger深度挖掘其功能是必不可少的过程.

配置xdebug与phpstorm工作是非常简单的,但是当两个人同时尝试用相同的IP在同一个远程开发环境中对同一段代码进行debug的时候,这件事情就变得非常微妙,这个时候xdebug无法分别出到底是谁在对代码进行debug.

所以你可以看一下单用户和多用户在配置xdebug时的区别.我会在下面对两者都作出介绍.

单个用户配置phpstorm xdebug 步骤

这有一张单独用户的xdebug工作图
单独用户xdebug图

  • php.ini中做如下配置:
    php.ini

  • 在phpstorm中做如下配置

single-debug-port.png

  • 确保phpstorm是在端口监听状态
    red-to-green.png
  • 下面在你的代码的某处设一个断点
  • 现在你已经可以在你的浏览器中进行debug对话了.这里设置了一个cookie所以服务端的xdebug知道如何执行你的debug需求.
    bookmarklet1.png
  • 在你的浏览器中浏览到'断点'页面(比如你的wordpress主页),如果php+xdebug发现了一个断点,它会发送debug数据到你的IDE.

恭喜你,到现在为止单用户的xdebug配置已经完成了!

未完待续...

散列函数time33学习随笔

年底项目任务中,忙里偷闲更新一篇.
众所周知,PHP拥有一个万能的数据结构--Array.这货实在是太易用太强大了,导致PHP程序员在程序员界都混不下去了.使用PHP的Array几乎可以实现在大学数据结构课本里出现的所有数据结构.
实际上在PHP内部,Array是由Zend引擎中的Zend HashTable实现的.其实不光是Array,包括各种常量,变量,函数体,class等都是用它来组织的.
在PHP的源代码里找到zend_hash.c后不难发现,zend hashtable包含两个结构体,分别是bucket

typedef struct bucket {
ulong h;       /* Used for numeric indexing */
uint nKeyLength;     /* key 长度 */
void *pData;      /* 指向Bucket中保存的数据的指针 */
void *pDataPtr;     /* 指针数据 */
struct bucket *pListNext;   /* 指向HashTable桶列中下一个元素 */
struct bucket *pListLast;    /* 指向HashTable桶列中前一个元素 */
struct bucket *pNext;    /* 指向具有同一个hash值的桶列的后一个元素 */
struct bucket *pLast;    /* 指向具有同一个hash值的桶列的前一个元素 */
char arKey[1];      /* 必须是最后一个成员,key名称*/
} Bucket;

以及_hashtable

typedef struct _hashtable {
uint nTableSize;
uint nTableMask;
uint nNumOfElements;
ulong nNextFreeElement;
Bucket *pInternalPointer;
Bucket *pListHead;
Bucket *pListTail; 
Bucket **arBuckets;
dtor_func_t pDestructor;
zend_bool persistent;
unsigned char nApplyCount;
zend_bool bApplyProtection;
#if ZEND_DEBUG
int inconsistent;
#endif
} HashTable;

这篇博文的重点并不在这里,相信每一个从事PHP行业的职业PHPer都对这些烂熟于心了.今天主要学习一下PHP使用的DJBX33A哈希算法
DJBX33A (Daniel J. Bernstein, Times 33 with Addition)普遍叫做time33算法,这个算法被广泛运用与多个软件项目,它是已知的最好的哈希算法之一,在处理以字符串为键值的哈希时,有着极快的计算效率和很好哈希分布.
如果用映射关系来表达的话就是如下形式,很简单:

hash(i) = hash(i-1) * 33 + str[i]

以下是PHP内部使用的time33版本:

inline unsigned time33(char const*str, int len) 
{ 
     unsigned long hash = 5381; 
     /* variant with the hash unrolled eight times */ 
     for (; len >= 8; len -= 8) { 
         hash = ((hash << 5) + hash) + *str++; 
         hash = ((hash << 5) + hash) + *str++; 
         hash = ((hash << 5) + hash) + *str++; 
         hash = ((hash << 5) + hash) + *str++; 
        hash = ((hash << 5) + hash) + *str++; 
        hash = ((hash << 5) + hash) + *str++; 
        hash = ((hash << 5) + hash) + *str++; 
        hash = ((hash << 5) + hash) + *str++; 
    } 
    switch (len) { 
        case 7: hash = ((hash << 5) + hash) + *str++; /* fallthrough... */ 
        case 6: hash = ((hash << 5) + hash) + *str++; /* fallthrough... */ 
        case 5: hash = ((hash << 5) + hash) + *str++; /* fallthrough... */ 
        case 4: hash = ((hash << 5) + hash) + *str++; /* fallthrough... */ 
        case 3: hash = ((hash << 5) + hash) + *str++; /* fallthrough... */ 
        case 2: hash = ((hash << 5) + hash) + *str++; /* fallthrough... */ 
        case 1: hash = ((hash << 5) + hash) + *str++; break; 
        case 0: break; 
    } 
    return hash; 
} 

用位运算代替乘法,效率更高.待续..

抽奖程序中随机概率的测试

最近一个项目里关于抽奖活动的概率引发了一些争执,
讲一下整个抽奖流程:
一共有M种元素,用户集齐其中的N种即算中奖,M种元素获得的概率都不相同.然后用户每天有T次机会可以抽奖,其中满足条件T>M;另说明我不是做游戏的,对于这方面来说有些欠缺,只能摸着石头过河,一段代码来验证概率是否合理.

$arr = array(
    'h1' => 30,
    'h2' => 30,
    'h3' => 8,
    'h4' => 8,
    'h5' => 8,
    'h6' => 8,
    'h7' => 8,
    'h8' => 5,
    ...
);

$lucky = array();
foreach( $arr as $k=>$v )
{
    $lucky += array_fill( count($lucky),$v,$k );
}

$user = array();
$limit = array();
$j = 0;
//采样数量$k
for( $k =0; $k < 1000;$k++ )
{
    $i = 1;
    while(true)
    {
        $a = $lucky[mt_rand(0,99)];
        if( !in_array( $a, $user ) )
        {
            $user[] = $a;
        }
            //达到获奖条件N
        if( count($user) >N )
        {
            $user = array();
            break;
        }
        $i++;
    }

    //用户每天有T次机会
    if( $i <= T )
    {
        $j++;
    }

    $limit[] = $i;

}

//这里得到采样中达到获奖资格平均需要多少次抽奖
var_dump(array_sum( $limit )/1000);

//得到在$k中有多少人可以在抽奖资格内的中奖
echo $k.'人中有多少人第一天能中奖'.($j);