php防CC攻击代码

Post by agang 2012-2-1 14:36 Wednesday

特别是用虚拟主机的用户,如果CPU超载将会出现“service unariable”的提示。关于超载的因素有很多,比如网页结构不合理,流量过大等。其中还有一个可能会出现的恶意因素,就是CC攻击。


  所谓的CC攻击就是对方利用程序或一些代理对您的网站进行不间断的访问,造成您的网站处理不了而处于当机状态。这种时候您的统计系统(可能是量子、百度等)当然也是统计不到的。不过我们可以借助于一些防攻击的软件来实现,不过效果有时并不明显。下面我提供一段PHP的代码,可以起到一定的防CC效果。

 

  主要功能:在3秒内连续刷新页面5次以上将指向本机 http://127.0.0.1

 

  代码如下:

$P_S_T  = $t_array[0] + $t_array[1]; 
$timestamp = time();

session_start(); 
$ll_nowtime = $timestamp ; 
if (session_is_registered('ll_lasttime')){ 
$ll_lasttime = $_SESSION['ll_lasttime']; 
$ll_times = $_SESSION['ll_times'] + 1; 
$_SESSION['ll_times'] = $ll_times; 
}else{ 
$ll_lasttime = $ll_nowtime; 
$ll_times = 1; 
$_SESSION['ll_times'] = $ll_times; 
$_SESSION['ll_lasttime'] = $ll_lasttime; 

if (($ll_nowtime - $ll_lasttime)<3){ 
if ($ll_times>=5){ 
  header(sprintf("Location: %s",'http://127.0.0.1')); 
  exit; 

}else{ 
  $ll_times = 0; 
$_SESSION['ll_lasttime'] = $ll_nowtime; 
$_SESSION['ll_times'] = $ll_times; 
}  
    3表示时间间隔,5表示刷新次数

    以上代码可以放在每个PHP文件的包含文件中,这样每页均可起到防CC的效果。里面的参数也可以根据您自己的情况进行一些相应的设置。
 

0

总结的一些PHP开发中的tips

Post by agang 2012-1-30 17:03 Monday

开发习惯和PHP代码:
1、准确的理解各种概念。现在的新东西层出不穷,望文生义和一知半解对开发工作有害无益;

2、代码美观,适当的空行、缩进,空格,这样能更容易理解代码段的意思;

3、一定要写注释,而且要恰当的注释,要不然后面的维护工作或者接手代码的人会痛哭不已;

4、静态方法、类访问权限、接口、抽象类应该综合起来使用,发挥各自特点;

5、不要复制粘贴,即使是要用到现成的代码,也要一行一行的审阅后,再加入到新项目,因为经验告诉我们,这太容易出错了,对于使用开源类这种大段代码更需要;

6、变量都要初始化;

7、不要只处理error,而忽略warning和notice,这可能会导致日后的莫名其妙的问题,项目在开发状态下应该是error_reporting( E_ALL  ^  E_NOTICE ),等到发布的外网生产环境时,应关闭所有错误报告display_errors=Off,error_reporting(0)网友 pAUL gAO分享了他们更合理的方案,error_reporting(E_ALL | E_STRICT),并且在生产环境中记录错误日志

8、记录一些必要的错误日志,比如写文件失败、写memcache失败,socket连接失败、读写数据库失败,日志能够帮助出现问题时的快速定位,外部生产环境我个人是强烈建议关闭所有错误报告的;

9、用try、catch捕获异常,对代码的健壮有帮助,常常在API接口中碰到,这样子显得友好多了;

10、双引号中出现的变量建议加上大括号,至于是”${nider}at gmail.com”还是”{$tom}at zendstudio.net”看个人习惯,我更喜欢后面一种;

11、尽量少的if else嵌套层数,也许你要表达一个非常复杂的逻辑算法,但这样做至少能让代码逻辑更清晰

12、多阅读网上开源项目的优秀代码(不是优秀项目的开源代码),吸取其中值得借鉴的地方

13、语言包用sprintf的格式化来做是多么惬意的一件事啊!

14、写缓存并不总是要先serialize一次的

15、AJAX传数据的时候,不要将数据库查出的数组直接json_encode后传给客户端,这样做不仅有一定的安全风险(字段名暴露),而且一些不需要的数据被传出浪费带宽,这条同样适用于API接口

16、要记得处理魔术变量,我的方法是直接关闭,当然也可以获取开关状态来避免传输数据被处理两次的问题

17、用$GLOBALS['var']代替global $var

18、不能轻易的die掉程序,尤其是在方法内部

19、require、require_once、include、include_once有着略微不同的应用场景

20、为了最大限度的使得写入缓存成功,可以结合重试次数+usleep,我一般重试3次,还不行那就记下一条log了

21、PHP的常量是个非常好的东西,很多开源项目中用一整个文件来定义要用到的常量

22、尽可能的使用绝对路径寻找文件

23、autoload是个很灵活的东西

24、最好用上set_error_handler和set_exception_handler,那显得你的项目更完美

25、PHP的引用类型是很高效的,在进行复杂运算时建议使用

26、@符号抑制错误是很耗性能的,因此尽可能的找到替代方案

MYSQL部分:
1、SQL语句用双引号,其中的值都用单引号,例如”INSERT INTO gril SET money=’{$iMaxMoney}’,age=’18′”

2、用mysqli扩展代替mysql扩展

2、用mysqli_real_escape_string和mysqli_escape_string处理传出sql语句中的变量

3、用mysqli_set_charset(mysqli->set_charset)代替 query “SET NAMES”

4、联合查询(JOIN)之前,考虑下各个表的数据量,不合适的话应该分开查,尤其是有缓存可用的时候

5、很多地方需要记录发生时间,但不是每一个表都需要,同样,不是每一个表都需要一个自增量作主键

6、很多时候为integer类型加上unsigned是很好的

7、INERT DELEYED、INSERT IGNORE、SELECT DISTINCT…这种语句通常有意想不到的好效果

8、varchar类型并不是不能超过255长度,而是超过了255,这个字段就不能建立索引了,所以,看你的实际需要了

暂时就想到这么多,等再想到的继续update吧。想到什么写什么,没有什么条理性,多多包涵了,如果这些对你有点滴帮助,那我就感到非常开心了。

0

PHP stdClass Object转array

Post by agang 2012-1-27 3:03 Friday

用json传过来的数组并不是标准的array,所以需要用这个函数进行转换。

function object_array($array)
{
   if(is_object($array))
   {
    $array = (array)$array;
   }
   if(is_array($array))
   {
    foreach($array as $key=>$value)
    {
     $array[$key] = object_array($value);
    }
   }
   return $array;
}

0

PHP 读取大文件

Post by agang 2012-1-19 0:23 Thursday

PHP 读取大文件

最近在工作中遇到了需要读取系统日志的问题,日志文件很大,大概在1G以上甚至更大,随即研究了读取得方法,直接使用PHP自带的函数就可以解决这几个问题,但是绝对不能使用file和file_get_contents,这两个函数是一次性将文件全部加载进来,如果文件在几十M 还是可以的,但是稍大的文件时不能用的,内存是会溢出的,贴个自己的方法,欢迎大家指教!

 

代码

<?


*/

* @param String $filename 文件地址

* @param Int $count 读取得行数

* @param String $sep 每行的分隔标记

* @return String 返回结果

*/

function readBigFile($filename, $count = 20, $tag = “\r\n”) {

$content = ”;//最终内容

$_current = ”;//当前读取内容寄存

$step= 1;//每次走多少字符

$tagLen = strlen($tag);

$start = 0;//起始位置

$i = 0;//计数器

$handle = fopen($filename,’r+’);//读写模式打开文件,指针指向文件头

while($i < $count && !feof($handle)) { //文件没有到结尾和小鱼需要读取得行数时

fseek($handle, $start, SEEK_SET);//指针设置在文件开头

$_current = fread($handle,$step);//读取文件

$content .= $_current;//组合字符串

$start += $step;//依据步长向前移动

//依据分隔符的长度截取字符串最后免得几个字符

$substrTag = substr($content, -$tagLen);

if ($substrTag == $tag) { //判断是否为判断是否是换行或其他分隔符

$i++;

}

}

//关闭文件

fclose($handle);

//返回结果

return $content;

}

$filename = ‘E:/2010log.log’;//需要读取的文件

$tag = “\r\n”;//行分隔符 注意这里必须用双引号

$count = 20;//读取行数

$data = readBigFile($filename,$count,$tag);

echo $data;
?>

 

PHP还有其他方法能够解决,比如system函数,不足之处还望指正!

0

取得URL的根域名

Post by agang 2012-1-13 3:32 Friday

<?php #author lonely
class rootDomain{
    private static $self;
    private $domain=null;
    private $host=null;
    private $state_domain;
    private $top_domain;
    /**
     * 取得域名分析实例
     * Enter description here ...
     */
    public function instace(){
        if(!self::$self)
            self::$self=new self();
        return self::$self;
    }
    private function  __construct(){
        $this->state_domain=array(
            'al','dz','af','ar','ae','aw','om','az','eg','et','ie','ee','ad','ao','ai','ag','at','au','mo','bb','pg','bs','pk','py','ps','bh','pa','br','by','bm','bg','mp','bj','be','is','pr','ba','pl','bo','bz','bw','bt','bf','bi','bv','kp','gq','dk','de','tl','tp','tg','dm','do','ru','ec','er','fr','fo','pf','gf','tf','va','ph','fj','fi','cv','fk','gm','cg','cd','co','cr','gg','gd','gl','ge','cu','gp','gu','gy','kz','ht','kr','nl','an','hm','hn','ki','dj','kg','gn','gw','ca','gh','ga','kh','cz','zw','cm','qa','ky','km','ci','kw','cc','hr','ke','ck','lv','ls','la','lb','lt','lr','ly','li','re','lu','rw','ro','mg','im','mv','mt','mw','my','ml','mk','mh','mq','yt','mu','mr','us','um','as','vi','mn','ms','bd','pe','fm','mm','md','ma','mc','mz','mx','nr','np','ni','ne','ng','nu','no','nf','na','za','aq','gs','eu','pw','pn','pt','jp','se','ch','sv','ws','yu','sl','sn','cy','sc','sa','cx','st','sh','kn','lc','sm','pm','vc','lk','sk','si','sj','sz','sd','sr','sb','so','tj','tw','th','tz','to','tc','tt','tn','tv','tr','tm','tk','wf','vu','gt','ve','bn','ug','ua','uy','uz','es','eh','gr','hk','sg','nc','nz','hu','sy','jm','am','ac','ye','iq','ir','il','it','in','id','uk','vg','io','jo','vn','zm','je','td','gi','cl','cf','cn','yr'
        );
        $this->top_domain=array('com','edu','gov','int','mil','net','org','biz','info','pro','name','museum','coop','aero','xxx','idv','me','mobi');
        $this->url=$_SERVER['HTTP_HOST'];
    }
    /**
     * 设置URL
     * Enter description here ...
     * @param string $url
     */
    public function setUrl($url=null){
        $url==null?$this->url:$url;
        if($url==null)return $this;
        if(!preg_match("/^http::/is", $url))
            $url="http://".$url ;
        $url=parse_url(strtolower($url));
        $urlarr=explode(".", $url['host']);
        $count=count($urlarr);
        if ($count<=2){
            $this->domain=$url;
        }else if ($count>2){
            $last=array_pop($urlarr);
            $last_1=array_pop($urlarr);
            if(in_array($last, $this->top_domain)){
                $this->domain=$last_1.'.'.$last;
                $this->host=implode('.', $urlarr);
            }else if (in_array($last, $this->state_domain)){
                $last_2=array_pop($urlarr);
                if(in_array($last_1, $this->top_domain)){
                    $this->domain=$last_2.'.'.$last_1.'.'.$last;
                    $this->host=implode('.', $urlarr);
                }else{
                    $this->host=implode('.', $urlarr).$last_2;
                    $this->domain=$last_1.'.'.$last;
                }
            }
        }
        return $this;
    }
    /**
     * 取得域名
     * Enter description here ...
     */
    public function getDomain(){
        return $this->domain;
    }
    /**
     * 取得主机
     * Enter description here ...
     */
    public function getHost(){
        return $this->host;
    }
}

echo $dom=rootDomain::instace()->setUrl(null)->getHost();
echo $dom=rootDomain::instace()->setUrl('test.test.cn')->getHost();
?>
 

0

25个PHP游戏编程脚本代码,时时彩开发者必备

Post by agang 2011-12-26 3:32 Monday

简单的掷骰器

许多游戏和游戏系统都需要骰子。让我们先从简单的部分入手:掷一个六面骰子。实际上,滚动一个六面骰子就是从 1 到 6 之间选择一个随机数字。在 PHP 中,这十分简单:echo rand(1,6);。

在许多情况下,这基本上很简单。但是在处理机率游戏时,我们需要一些更好的实现。PHP 提供了更好的随机数字生成器:mt_rand()。在不深入研究两者差别的情况下,可以认为 mt_rand 是一个更快、更好的随机数字生成器:echo mt_rand(1,6);。如果把该随机数字生成器放入函数中,则效果会更好。

清单 1. 使用 mt_rand() 随机数字生成器函数

    function roll () { 
    return mt_rand(1,6); 
    } 
    echo roll();

然后可以把需要滚动的骰子类型作为参数传递给函数。

清单 2. 将骰子类型作为参数传递

    function roll ($sides) { 
    return mt_rand(1,$sides); 
    } 
    echo roll(6);  // roll a six-sided die 
    echo roll(10);  // roll a ten-sided die 
    echo roll(20);  // roll a twenty-sided die

从这里开始,我们可以继续根据需要一次滚动多个骰子,返回结果数组;也可以一次性滚动多个不同类型的骰子。但是大多数任务都可以使用这个简单的脚本。

随机名称生成器

如果正在运行游戏、编写故事或者一次性创建大批字符,有时会疲于应付不断出现的新名字。让我们看一看可用于解决此问题的一个简单随机名称生成器。首先,让我们创建两个简单数组 — 一个用于名字,一个用于姓氏。

清单 3. 名字和姓氏的两个简单数组

    $male = array( 
    "William", 
    "Henry", 
    "Filbert", 
    "John", 
    "Pat", 
    ); 
    $last = array( 
    "Smith", 
    "Jones", 
    "Winkler", 
    "Cooper", 
    "Cline", 
    );

然后就可以从每个数组中选择一个随机元素:echo $male[array_rand($male)] . ' ' . $last[array_rand($last)];。要一次性提取多个名称,只需混合数组并根据需要提取。

清单 4. 混合名称数组

    shuffle($male); 
    shuffle($last); 
    for ($i = 0; $i <= 3; $i++) { 
    echo $male[$i] . ' ' . $last[$i]; 
    }

基于此基本概念,我们可以创建保存名字和姓氏的文本文件。如果在文本文件的每一行中存放一个名字,则可以轻松地用换行符分隔文件内容以构建源代码数组。

清单 5. 创建名称的文本文件

    $male = explode('\n', file_get_contents('names.female.txt')); 
    $last = explode('\n', file_get_contents('names.last.txt'));

构建或查找一些好的名字文件(代码归档 中附带了一些文件),此后我们绝不再需要为名字烦恼。

场景生成器

利用构建名字生成器使用的相同基本原理,我们可以构建场景生成器。此生成器不但在角色扮演游戏中十分有用,而且在需要用到伪随机环境集合(可用于角 色扮演、即兴创作、写作等情况)的情况下也十分有用。我最喜欢的游戏之一,Paranoia 在其 GM Pack 中包括了 “任务混合器(mission blender)”。任务混合器可用于在快速滚动骰子时整合完整任务。让我们整合自己的场景生成器。

考虑以下场景:您醒来后发现自己迷失于丛林中。您知道自己必须赶去纽约,但是不知道原因。您可以听到附近的狗叫声及清晰的敌方搜寻者的声音。您浑身发冷、不住颤抖,而且没有武器。该场景中的每一句话都介绍场景的特定方面:

“您醒来后发现自己迷失于丛林中” — 这句话将建立设置。

“您知道自己必须赶去纽约” — 这句话将描述目标。

“您可以听到狗叫声” — 这句话将介绍敌人。

“您浑身发冷、不住颤抖,而且没有武器” — 这句话将添加复杂度。

就像创建名字和姓氏的文本文件一样,首先分别创建设置、目标、敌人和复杂度的文本文件。代码归档中附带了样例文件。在拥有这些文件后,生成场景的代码与生成名称的代码基本相同。

清单 6. 生成场景

    $settings = explode("\n", file_get_contents('scenario.settings.txt')); 
    $objectives = explode("\n", file_get_contents('scenario.objectives.txt')); 
    $antagonists = explode("\n", file_get_contents('scenario.antagonists.txt')); 
    $complicati**** = explode("\n", file_get_contents('scenario.complicati****.txt')); 
    shuffle($settings); 
    shuffle($objectives); 
    shuffle($antagonists); 
    shuffle($complicati****); 
    echo $settings[0] . ' ' . $objectives[0] . ' ' . $antagonists[0] . ' '
    . $complicati****[0] . "\n";

我们可以通过添加新文本文件向场景中添加元素,也可能希望添加多重复杂度。添加到基本文本文件中的内容越多,场景随时间的变化就越多。

牌组创建器(Deck builder)和装备(shuffler)

如果您要玩纸牌并且要处理与纸牌相关的脚本,我们需要用装备中的工具整合一副牌组构建器。首先,让我们构建一副标准纸牌。需要构建两个数组 — 一个用于保存同花色的组牌,而另一个用于保存牌面。如果稍后需要添加新组牌或牌类型,则这样做将获得很好的灵活性。

清单 7. 构建一副标准扑克牌

    $suits = array ( 
    "Spades", "Hearts", "Clubs", "Diamonds"
    ); 
    $faces = array ( 
    "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", 
    "Nine", "Ten", "Jack", "Queen", "King", "Ace"
    );

然后构建一副牌数组来保存所有纸牌值。只需使用一对 foreach 循环即可完成此操作。

清单 8. 构建一副牌数组

    $deck = array(); 
    foreach ($suits as $suit) { 
    foreach ($faces as $face) { 
    $deck[] = array ("face"=>$face, "suit"=>$suit); 
    } 
    }

在构建了一副扑克牌数组后,我们可以轻松地洗牌并随机抽出一张牌。

清单 9. 洗牌并随机抽出一张牌

    shuffle($deck); 
    $card = array_shift($deck); 
    echo $card['face'] . ' of ' . $card['suit'];

现在,我们就获得了抽取多副牌或构建多层牌盒(multideck shoe)的捷径。

胜率计算器:发牌

由于构建扑克牌时会分别跟踪每张牌的牌面和花色,因此可以通过编程方式利用这副牌来计算得到特定牌的几率。首先每只手分别抽出五张牌。

清单 10. 每只手抽出五张牌

    $hands = array(1 => array(), 2=>array()); 
    for ($i = 0; $i < 5; $i++) { 
    $hands[1][] = implode(" of ", array_shift($deck)); 
    $hands[2][] = implode(" of ", array_shift($deck)); 
    }

然后可以查看这副牌,看看剩余多少张牌以及抽到特定牌的机率是多少。查看剩余的牌数十分简单。只需要计算 $deck 数组中包含的元素数。要获得抽到特定牌的机率,我们需要一个函数来遍历整副牌并估算其余牌以查看是否匹配。

清单 11. 计算抽到特定牌的几率

    function calculate_odds($draw, $deck) { 
    $remaining = count($deck); 
    $odds = 0; 
    foreach ($deck as $card) { 
    if (  ($draw['face'] == $card['face'] && $draw['suit'] == 
    $card['suit'] ) || 
    ($draw['face'] == '' && $draw['suit'] == $card['suit'] ) || 
    ($draw['face'] == $card['face'] && $draw['suit'] == '' ) ) { 
    $odds++; 
    } 
    } 
    return $odds . ' in ' $remaining; 
    }

现在可以选出尝试抽出的牌。为了简单起见,传入看上去类似某张牌的数组。我们可以查找特定的一张牌。

清单 12. 查找指定的一张牌

    $draw = array('face' => 'Ace', 'suit' => 'Spades'); 
    echo implode(" of ", $draw) . ' : ' . calculate_odds($draw, $deck);

或者可以查找指定牌面或花色的牌。

清单 13. 查找指定牌面或花色的牌

    $draw = array('face' => '', 'suit' => 'Spades'); 
    $draw = array('face' => 'Ace', 'suit' => '');

简单的扑克发牌器

现在已经得到牌组构建器和一些工具,可以帮助计算出抽出特定卡的机率,我们可以整合一个真正简单的发牌器来进行发牌。出于本例的目的,我们将构建一 个可以抽出五张牌的发牌器。发牌器将从整副牌中提供五张牌。使用数字指定需要放弃哪些牌,并且发牌器将用一副牌中的其他牌替换这些牌。我们无需指定发牌限 制或特殊规则,但是您可能会发现这些是非常有益的个人经验。

如上一节所示,生成并洗牌,然后每只手五张牌。按数组索引显示这些牌,以便可以指定返回哪些牌。您可以使用表示要替换哪些牌的复选框来完成此操作。

清单 14. 使用复选框表示要替换的牌

    foreach ($hand as $index =>$card) { 
    echo "< span=""> . $index . "]'>  <>
    " . $card['face'] . ' of ' . $card['suit'] . ""; 
    }

然后,计算输入 array $_POST['card'],查看哪些牌已被选择用于替换。

清单 15. 计算输入

    $i = 0; 
    while ($i < 5) { 
    if (isset($_POST['card'][$i])) { 
    $hand[$i] = array_shift($deck); 
    } 
    }

使用此脚本,您可以尝试找到处理特定一组牌的最佳方法。

Hangman 游戏

Hangman 实质上是一款猜字游戏。给定单词的长度,我们使用有限的几次机会猜这个单词。如果猜出了出现在该单词中的一个字母,则填充该字母出现的所有位置。在猜错若 干次(通常为六次)后,您就输了比赛。要构建一个简陋的 hangman 游戏,我们需要从单词列表开始。现在,让我们把单词列表制作成一个简单的数组。

清单 16. 创建单词列表

    $words = array ( 
    "giants", 
    "triangle", 
    "particle", 
    "birdhouse", 
    "minimum", 
    "flood"
    );

使用前面介绍的技术,我们可以把这些单词移动到外部单词列表文本文件中,然后根据需要导入。

在得到单词列表后,需要随机选出一个单词,将每个字母显示为空,然后开始猜测。我们需要在每次进行猜测时跟踪正确和错误的猜测。只需序列化猜测数组并在每次猜测时传递它们,就可实现跟踪目的。如果需要阻止人们通过查看页面源代码侥幸猜对,则需要执行一些更安全的操作。

构建数组以保存字母和正确/错误的猜测。对于正确的猜测,我们将用字母作为键并用句点作为值填充数组。

清单 17. 构建保存字母和猜测结果的数组

    $letters = array('a','b','c','d','e','f','g','h','i','j','k','l','m','n','o', 
    'p','q','r','s','t','u','v','w','x','y','z'); 
    $right = array_fill_keys($letters, '.'); 
    $wrong = array();

现在需要一些代码来评估猜测并在完成猜字游戏的过程中显示该单词。

清单 18. 评估猜测并显示进度

    if (stristr($word, $guess)) { 
    $show = ''; 
    $right[$guess] = $guess; 
    $wordletters = str_split($word); 
    foreach ($wordletters as $letter) { 
    $show .= $right[$letter]; 
    } 
    } else { 
    $show = ''; 
    $wrong[$guess] = $guess; 
    if (count($wrong) == 6) { 
    $show = $word; 
    } else { 
    foreach ($wordletters as $letter) { 
    $show .= $right[$letter]; 
    } 
    } 
    }

在源代码归档 中,可以看到如何序列化猜测数组并将该数组从一次猜测传递到另一次猜测中。

纵横字谜助手

我知道这样做不合适,但是有时在玩纵横拼字谜时,您不得不费劲地找出以 C 开头并以 T 结尾、包含五个字母的单词。使用为 Hangman 游戏构建的相同单词列表,我们可以轻松地搜索符合某个模式的单词。首先,找到一种传输单词的方法。为了简单起见,用句点替换缺少的字母:$guess = "c...t";。由于正则表达式将把句点处理为单个字符,因此我们可以轻松地遍历单词列表以查找匹配。

清单 19. 遍历单词列表

    foreach ($words as $word) { 
    if (preg_match("/^" . $_POST['guess'] . "$/",$word)) { 
    echo $word . "\n"; 
    } 
    }

根据单词列表的质量及猜测的准确度,我们应当能够得到合理的单词列表以用于可能的匹配。您必须自己决定 “表示 ‘不按规则玩’ 的由五个字母组成的单词” 的谜底是 “chest” 还是 “cheat”。

米德里比斯

米德里比斯是一款文字游戏,玩家在游戏中得到一个简短的故事并用同一类型的不同单词替换主要类型的单词,从而创建同一个故事的更无聊的新版本。阅读 以下文本:“I was walking in the park when I found a lake. I jumped in and swallowed too much water. I had to go to the hospital.” 开始用其他单词标记替换单词类型。开始和结束标记带有下划线用于阻止意外的字符串匹配。

清单 20. 用单词标记替换单词类型

    $text = "I was _VERB_ing in the _PLACE_ when I found a _NOUN_. 
    I _VERB_ed in, and _VERB_ed too much _NOUN_.  I had to go to the _PLACE_.";

接下来,创建几个基本单词列表。对于本例,我们也不会做得太复杂。

清单 21. 创建几个基本单词列表

    $verbs = array('pump', 'jump', 'walk', 'swallow', 'crawl', 'wail', 'roll'); 
    $places = array('park', 'hospital', 'arctic', 'ocean', 'grocery', 'basement', 
    'attic', 'sewer'); 
    $nouns = array('water', 'lake', 'spit', 'foot', 'worm', 
    'dirt', 'river', 'wankel rotary engine');

现在可以重复地评估文本来根据需要替换标记。

清单 22. 评估文本

    while (preg_match("/(_VERB_)|(_PLACE_)|(_NOUN_)/", $text, $matches)) { 
    switch ($matches[0]) { 
    case '_VERB_' : 
    shuffle($verbs); 
    $text = preg_replace($matches[0], current($verbs), $text, 1); 
    break; 
    case '_PLACE_' : 
    shuffle($places); 
    $text = preg_replace($matches[0], current($places), $text, 1); 
    break; 
    case '_NOUN_' : 
    shuffle($nouns); 
    $text = preg_replace($matches[0], current($nouns), $text, 1); 
    break; 
    } 
    } 
    echo $text;

很明显,这是一个简单而粗糙的示例。单词列表越精确,并且花在基本文本上的时间越多,结果就越好。我们已经使用了文本文件创建名称列表及基本单词列表。使用相同原则,我们可以创建按类型划分的单词列表并使用这些单词列表创建更加变化多端的米德里比斯游戏。

乐透机

全部选中乐透的六个正确号码 —— 退一步说 —— 在统计学上是不可能的。不过,许多人仍然花钱去玩,而且如果您喜欢号码,则查看趋势图可能很有趣。让我们构建一个脚本,该脚本将允许跟踪赢奖号码并在列表中提供选择次数最少的 6 个号码。

(免责声明:这不会帮助您中乐透奖,因此请不要花钱购买奖券。这只是为了娱乐)。

把赢奖的乐透选择保存到文本文件中。用逗号分隔各个号码并把每组号码放在单独一行中。使用换行符分隔文件内容并使用逗号分隔行后,可以得到类似清单 23 的内容。

清单 23. 把选择的赢奖乐透保存到文本文件中

    $picks = array( 
    array('6', '10', '18', '21', '34', '40'), 
    array('2', '8', '13', '22', '30', '39'), 
    array('3', '9', '14', '25', '31', '35'), 
    array('11', '12', '16', '24', '36', '37'), 
    array('4', '7', '17', '26', '32', '33') 
    );

很明显,这不足以成为绘制统计数据的基本文件。但是它是一个开端,并且足以演示基本原理。

设置一个基本数组以保存选择范围。例如,如果选择 1 到 40 之间(例如,$numbers = array_fill(1,40,0);)的号码,则遍历我们的选择,递增相应的匹配值。

清单 24. 遍历选择

    foreach ($picks as $pick) { 
    foreach ($pick as $number) { 
    $numbers[$number]++; 
    } 
    }

最后,根据值将号码排序。此操作应当会把最少选择的号码放在数组的前部。

清单 25. 根据值将号码排序

    asort($numbers); 
    $pick = array_slice($numbers,0,6,true); 
    echo implode(',', array_keys($pick));

通过有规律地向包含中奖号码列表的文本文件添加实际的乐透中奖号码,可以发现选号的长期趋势。查看某些号码的出现频率十分有趣。

0

PHP mysql 事务处理实例

Post by agang 2011-12-18 1:01 Sunday

事务是必须满足4个条件(ACID):原子性(Autmic)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)

原子性(Autmic):事务在执行性,要做到“要么不做,要么全做!”,就是说不允许事务部分得执行。即使因为故障而使事务不能完成,在rollback时也要消除对数据库得影响!

一致性(Consistency):事务得操作应该使使数据库从一个一致状态转变倒另一个一致得状态!就拿网上购物来说吧,你只有即让商品出库,又让商品进入顾客得购物篮才能构成事务!

隔离性(Isolation):如果多个事务并发执行,应象各个事务独立执行一样!

持久性(Durability):一个成功执行得事务对数据库得作用是持久得,即使数据库应故障出错,也应该能够恢复!

MYSQL的事务处理主要有两种方法。
1、用begin,rollback,commit来实现
        begin 开始一个事务
        rollback 事务回滚
        commit  事务确认
        rollback和commit不能并列使用,当你同时使用,只有前面的一个有效,而后面的无效,即是你或执行commit或执行rollback
2、直接用set来改变mysql的自动提交模式
          MYSQL默认是自动提交的,也就是你提交一个QUERY,它就直接执行!我们可以通过
          set autocommit=0   禁止自动提交
          set autocommit=1 开启自动提交
          来实现事务的处理。

注意当你用 set autocommit=0 的时候,你以后所有的SQL都将做为事务处理,直到你用commit确认或rollback结束,注意当你结束这个事务的同时也开启了个新的事务!按第一种方法只将当前的作为一个事务!

MYSQL中只有INNODB和BDB类型的数据表才能支持事务处理!其他的类型是不支持的!
***:一般MYSQL数据库默认的引擎是MyISAM,这种引擎不支持事务!如果要让MYSQL支持事务,可以自己手动修改:
方法如下:1.修改c:appservmysqlmy.ini文件,找到skip-InnoDB,在前面加上#,后保存文件。
2.在运行中输入:services.msc,重启mysql服务。
3.到phpmyadmin中,mysql->show engines;(或执行mysql->show variables like 'have_%'; ),查看InnoDB为YES,即表示数据库支持InnoDB了。
也就说明支持事务transaction了。
4.在创建表时,就可以为Storage Engine选择InnoDB引擎了。如果是以前创建的表,可以使用mysql->alter table table_name type=InnoDB;
或 mysql->alter table table_name engine=InnoDB;来改变数据表的引擎以支持事务。

 

实例一.

 

Php代码 
$conn = mysql_connect('localhost','root','root') or die ("数据连接错误!!!");   
mysql_select_db('test',$conn);   
mysql_query("set names 'GBK'"); //使用GBK中文编码;   
//开始一个事务   
mysql_query("BEGIN"); //或者mysql_query("START TRANSACTION");   
$sql = "INSERT INTO `user` (`id`, `username`, `sex`) VALUES (NULL, 'test1', '0')";   
$sql2 = "INSERT INTO `user` (`did`, `username`, `sex`) VALUES (NULL, 'test1', '0')";//这条我故意写错   
$res = mysql_query($sql);   
$res1 = mysql_query($sql2);    
if($res && $res1){   
mysql_query("COMMIT");   
echo '提交成功。';   
}else{   
mysql_query("ROLLBACK");   
echo '数据回滚。';   
}   
mysql_query("END");   

    $conn = mysql_connect('localhost','root','root') or die ("数据连接错误!!!");
    mysql_select_db('test',$conn);
    mysql_query("set names 'GBK'"); //使用GBK中文编码;
    //开始一个事务
    mysql_query("BEGIN"); //或者mysql_query("START TRANSACTION");
    $sql = "INSERT INTO `user` (`id`, `username`, `sex`) VALUES (NULL, 'test1', '0')";
    $sql2 = "INSERT INTO `user` (`did`, `username`, `sex`) VALUES (NULL, 'test1', '0')";//这条我故意写错
    $res = mysql_query($sql);
    $res1 = mysql_query($sql2); 
    if($res && $res1){
    mysql_query("COMMIT");
    echo '提交成功。';
    }else{
    mysql_query("ROLLBACK");
    echo '数据回滚。';
    }
    mysql_query("END");  

实例二

Php代码 
mysql_query("SET AUTOCOMMIT=0"); //设置mysql不自动提交,需自行用commit语句提交   
$sql = "INSERT INTO `user` (`id`, `username`, `sex`) VALUES (NULL, 'test1', '0')";   
$sql2 = "INSERT INTO `user` (`did`, `username`, `sex`) VALUES (NULL, 'test1', '0')";//这条我故意写错   
$res = mysql_query($sql);   
$res1 = mysql_query($sql2);    
if($res && $res1){   
mysql_query("COMMIT");   
echo '提交成功。';   
}else{   
mysql_query("ROLLBACK");   
echo '数据回滚。';   
}   
mysql_query("END"); //事务处理完时别忘记mysql_query("SET AUTOCOMMIT=1");自动提交  

    mysql_query("SET AUTOCOMMIT=0"); //设置mysql不自动提交,需自行用commit语句提交
    $sql = "INSERT INTO `user` (`id`, `username`, `sex`) VALUES (NULL, 'test1', '0')";
    $sql2 = "INSERT INTO `user` (`did`, `username`, `sex`) VALUES (NULL, 'test1', '0')";//这条我故意写错
    $res = mysql_query($sql);
    $res1 = mysql_query($sql2); 
    if($res && $res1){
    mysql_query("COMMIT");
    echo '提交成功。';
    }else{
    mysql_query("ROLLBACK");
    echo '数据回滚。';
    }
    mysql_query("END"); //事务处理完时别忘记mysql_query("SET AUTOCOMMIT=1");自动提交  
对于不支持事务的MyISAM引擎数据库可以使用表锁定的方法

//MyISAM & InnoDB 都支持,
/*
LOCK TABLES可以锁定用于当前线程的表。如果表被其它线程锁定,则造成堵塞,直到可以获取所有锁定为止。
UNLOCK TABLES可以释放被当前线程保持的任何锁定。当线程发布另一个LOCK TABLES时,或当与服务器的连接被关闭时,所有由当前线程锁定的表被隐含地解锁。
*/

Php代码 
mysql_query("LOCK TABLES `user` WRITE");//锁住`user`表   
$sql = "INSERT INTO `user` (`id`, `username`, `sex`) VALUES (NULL, 'test1', '0')";   
$res = mysql_query($sql);   
if($res){   
echo '提交成功。!';   
}else{   
echo '失败!';   
}   
mysql_query("UNLOCK TABLES");//解除锁定  

    mysql_query("LOCK TABLES `user` WRITE");//锁住`user`表
    $sql = "INSERT INTO `user` (`id`, `username`, `sex`) VALUES (NULL, 'test1', '0')";
    $res = mysql_query($sql);
    if($res){
    echo '提交成功。!';
    }else{
    echo '失败!';
    }
    mysql_query("UNLOCK TABLES");//解除锁定  

0

PHP效率优化方法

Post by agang 2011-12-2 20:21 Friday

2.尽量的少进行文件操作,虽然PHP的文件操作效率也不低的;

3.优化Select SQL语句,在可能的情况下尽量少的进行Insert、Update操作(在update上,我被恶批过);

4.尽可能的使用PHP内部函数(但是我却为了找个PHP里面不存在的函数,浪费了本可以写出一个自定义函数的时间,经验问题啊!);

5.循环内部不要声明变量,尤其是大变量:对象(这好像不只是PHP里面要注意的问题吧?);

6.多维数组尽量不要循环嵌套赋值;

7.在可以用PHP内部字符串操作函数的情况下,不要用正则表达式;

8.foreach效率更高,尽量用foreach代替while和for循环;

9.用单引号替代双引号引用字符串;

10.“用i+=1代替i=i+1。符合c/c++的习惯,效率还高”;

11.对global变量,应该用完就unset()掉;

0

史上最全最强的正则表达式

Post by agang 2011-11-30 17:55 Wednesday

匹配中文字符的正则表达式: [u4e00-u9fa5]  
评注:匹配中文还真是个头疼的事,有了这个表达式就好办了  
  
匹配双字节字符(包括汉字在内):[^x00-xff]  
评注:可以用来计算字符串的长度(一个双字节字符长度计2,ASCII字符计1)  
匹配空白行的正则表达式:ns*r  
评注:可以用来删除空白行  
匹配HTML标记的正则表达式:<(S*?)[^>]*>.*?|<.*? />  
评注:网上流传的版本太糟糕,上面这个也仅仅能匹配部分,对于复杂的嵌套标记依旧无能为力  
匹配首尾空白字符的正则表达式:^s*|s*$  
评注:可以用来删除行首行尾的空白字符(包括空格、制表符、换页符等等),非常有用的表达式  
匹配Email地址的正则表达式:w+([-+.]w+)*@w+([-.]w+)*.w+([-.]w+)*  
评注:表单验证时很实用  
匹配网址URL的正则表达式:[a-zA-z]+://[^s]*  
评注:网上流传的版本功能很有限,上面这个基本可以满足需求  
匹配帐号是否合法(字母开头,允许5-16字节,允许字母数字下划线):^[a-zA-Z][a-zA-Z0-9_]{4,15}$  
评注:表单验证时很实用  
匹配国内电话号码:d{3}-d{8}|d{4}-d{7}  
评注:匹配形式如 0511-4405222 或 021-87888822  
匹配腾讯QQ号:[1-9][0-9]{4,}  
评注:腾讯QQ号从10000开始  
匹配中国邮政编码:[1-9]d{5}(?!d)  
评注:中国邮政编码为6位数字  
匹配身份证:d{15}|d{18}  
评注:中国的身份证为15位或18位  
匹配ip地址:d+.d+.d+.d+  
评注:提取ip地址时有用  
  
最强验证日期的正则表达式,添加了闰年的验证  
  
这个日期正则表达式支持  
YYYY-MM-DD   
YYYY/MM/DD   
YYYY_MM_DD   
YYYY.MM.DD的形式  
  
match : 2008-2-29 2008/02/29  
  
not match : 2008-2-30     2007-2-29  
  
  
完整的正则表达式如下:  
((^((1[8-9]d{2})|([2-9]d{3}))([-/._])(10|12|0?[13578])([-/._])(3[01]|[12][0-9]|0?[1-9])$)|(^((1[8-9]d{2})|([2-9]d{3}))([-/._])(11|0?[469])([-/._])(30|[12][0-9]|0?[1-9])$)|(^((1[8-9]d{2})|([2-9]d{3}))([-/._])(0?2)([-/._])(2[0-8]|1[0-9]|0?[1-9])$)|(^([2468][048]00)([-/._])(0?2)([-/._])(29)$)|(^([3579][26]00)([-/._])(0?2)([-/._])(29)$)|(^([1][89][0][48])([-/._])(0?2)([-/._])(29)$)|(^([2-9][0-9][0][48])([-/._])(0?2)([-/._])(29)$)|(^([1][89][2468][048])([-/._])(0?2)([-/._])(29)$)|(^([2-9][0-9][2468][048])([-/._])(0?2)([-/._])(29)$)|(^([1][89][13579][26])([-/._])(0?2)([-/._])(29)$)|(^([2-9][0-9][13579][26])([-/._])(0?2)([-/._])(29)$))  
闰年的2月份有29天,因此匹配闰年日期格式为YYYY-MM-DD的正则表达式为:  
  
(([0-9]{2})(0[48]|[2468][048]|[13579][26])|((0[48]|[2468][048]|[3579][26])00))-02-29  
  
最后,将平年和闰年的日期验证表达式合并,我们得到最终的验证日期格式为YYYY-MM-DD的正则表达式为:  
  
(([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3})-(((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01]))|((0[469]|11)-(0[1-9]|[12][0-9]|30))|(02-(0[1-9]|[1][0-9]|2[0-8]))))|((([0-9]{2})(0[48]|[2468][048]|[13579][26])|((0[48]|[2468][048]|[3579][26])00))-02-29)  
  
DD/MM/YYYY格式的正则验证表达式为:  
  
(((0[1-9]|[12][0-9]|3[01])/((0[13578]|1[02]))|((0[1-9]|[12][0-9]|30)/(0[469]|11))|(0[1-9]|[1][0-9]|2[0-8])/(02))/([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3}))|(29/02/(([0-9]{2})(0[48]|[2468][048]|[13579][26])|((0[48]|[2468][048]|[3579][26])00)))  
  
  
匹配特定数字:  
^[1-9]d*$    //匹配正整数  
^-[1-9]d*$   //匹配负整数  
^-?[1-9]d*$   //匹配整数  
^[1-9]d*|0$  //匹配非负整数(正整数 + 0)  
^-[1-9]d*|0$   //匹配非正整数(负整数 + 0)  
^[1-9]d*.d*|0.d*[1-9]d*$   //匹配正浮点数  
^-([1-9]d*.d*|0.d*[1-9]d*)$  //匹配负浮点数  
^-?([1-9]d*.d*|0.d*[1-9]d*|0?.0+|0)$  //匹配浮点数  
^[1-9]d*.d*|0.d*[1-9]d*|0?.0+|0$   //匹配非负浮点数(正浮点数 + 0)  
^(-([1-9]d*.d*|0.d*[1-9]d*))|0?.0+|0$  //匹配非正浮点数(负浮点数 + 0)  
评注:处理大量数据时有用,具体应用时注意修正  
匹配特定字符串:  
^[A-Za-z]+$  //匹配由26个英文字母组成的字符串  
^[A-Z]+$  //匹配由26个英文字母的大写组成的字符串  
^[a-z]+$  //匹配由26个英文字母的小写组成的字符串  
^[A-Za-z0-9]+$  //匹配由数字和26个英文字母组成的字符串  
^w+$  //匹配由数字、26个英文字母或者下划线组成的字符串  
  
在使用RegularExpressionValidator验证控件时的验证功能及其验证表达式介绍如下:  
  
只能输入数字:“^[0-9]*$”  
只能输入n位的数字:“^d{n}$”  
只能输入至少n位数字:“^d{n,}$”  
只能输入m-n位的数字:“^d{m,n}$”  
只能输入零和非零开头的数字:“^(0|[1-9][0-9]*)$”  
只能输入有两位小数的正实数:“^[0-9]+(.[0-9]{2})?$”  
只能输入有1-3位小数的正实数:“^[0-9]+(.[0-9]{1,3})?$”  
只能输入非零的正整数:“^+?[1-9][0-9]*$”  
只能输入非零的负整数:“^-[1-9][0-9]*$”  
只能输入长度为3的字符:“^.{3}$”  
只能输入由26个英文字母组成的字符串:“^[A-Za-z]+$”  
只能输入由26个大写英文字母组成的字符串:“^[A-Z]+$”  
只能输入由26个小写英文字母组成的字符串:“^[a-z]+$”  
只能输入由数字和26个英文字母组成的字符串:“^[A-Za-z0-9]+$”  
只能输入由数字、26个英文字母或者下划线组成的字符串:“^w+$”  
验证用户密码:“^[a-zA-Z]w{5,17}$”正确格式为:以字母开头,长度在6-18之间,  
  
只能包含字符、数字和下划线。  
验证是否含有^%&',;=?$"等字符:“[^%&',;=?$x22]+”  
只能输入汉字:“^[u4e00-u9fa5],{0,}$”  
验证Email地址:“^w+[-+.]w+)*@w+([-.]w+)*.w+([-.]w+)*$”  
验证InternetURL:“^http://([w-]+.)+[w-]+(/[w-./?%&=]*)?$”  
验证电话号码:“^((d{3,4})|d{3,4}-)?d{7,8}$”  
  
正确格式为:“XXXX-XXXXXXX”,“XXXX-XXXXXXXX”,“XXX-XXXXXXX”,  
  
“XXX-XXXXXXXX”,“XXXXXXX”,“XXXXXXXX”。  
验证身份证号(15位或18位数字):“^d{15}|d{}18$”  
验证一年的12个月:“^(0?[1-9]|1[0-2])$”正确格式为:“01”-“09”和“1”“12”  
验证一个月的31天:“^((0?[1-9])|((1|2)[0-9])|30|31)$”  
  
正确格式为:“01”“09”和“1”“31”。  
  
匹配中文字符的正则表达式: [u4e00-u9fa5]  
匹配双字节字符(包括汉字在内):[^x00-xff]  
匹配空行的正则表达式:n[s| ]*r  
匹配HTML标记的正则表达式:/<(.*)>.*</1>|<(.*) />/   
匹配首尾空格的正则表达式:(^s*)|(s*$)  
匹配Email地址的正则表达式:w+([-+.]w+)*@w+([-.]w+)*.w+([-.]w+)*  
匹配网址URL的正则表达式:http://([w-]+.)+[w-]+(/[w - ./?%&=]*)?  
(1)应用:计算字符串的长度(一个双字节字符长度计2,ASCII字符计1)   
String.prototype.len=function(){return this.replace([^x00-xff]/g,"aa").length;}  
(2)应用:javascript中没有像vbscript那样的trim函数,我们就可以利用这个表达式来实现  
String.prototype.trim = function()  
{  
return this.replace(/(^s*)|(s*$)/g, "");  
}  
(3)应用:利用正则表达式分解和转换IP地址  
function IP2V(ip) //IP地址转换成对应数值  
{  
re=/(d+).(d+).(d+).(d+)/g //匹配IP地址的正则表达式  
if(re.test(ip))  
{  
return RegExp.$1*Math.pow(255,3))+RegExp.$2*Math.pow(255,2))+RegExp.$3*255+RegExp.$4*1  
}  
else  
{  
throw new Error("Not a valid IP address!")  
}  
}  
(4)应用:从URL地址中提取文件名的javascript程序  
s="http://www.nmi.cn/page1.htm ";  
s=s.replace(/(.*/){0,}([^.]+).*/ig,"$2") ; //Page1.htm  
(5)应用:利用正则表达式限制网页表单里的文本框输入内容  
用正则表达式限制只能输入中文:onkeyup="value=value.replace(/[^u4E00-u9FA5]/g,'') " onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^u4E00-u9FA5]/g,''))"  
用正则表达式限制只能输入全角字符: onkeyup="value=value.replace(/[^uFF00-uFFFF]/g,'') " onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^uFF00-uFFFF]/g,''))"  
用正则表达式限制只能输入数字:onkeyup="value=value.replace(/[^d]/g,'') "onbeforepaste= "clipboardData.setData('text',clipboardData.getData('text').replace(/[^d]/g,''))"  
用正则表达式限制只能输入数字和英文:onkeyup="value=value.replace(/[W]/g,'') "onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^d]/g,''  
 

0

PHP了解你的内存使用情况

Post by agang 2011-11-17 0:01 Thursday

PHP了解你的内存使用情况
 

为了优化你的脚本,你需要了解服务器上的RAM使用情况。这个代码片段将帮助你了解内存使用,并且打印初始、最终以及峰值使用情况。

 

echo "Initial: ".memory_get_usage()." bytes n";
/* prints
Initial: 361400 bytes
*/

// let's use up some memory
for ($i = 0; $i < 100000; $i++) {
 $array []= md5($i);
}

// let's remove half of the array
for ($i = 0; $i < 100000; $i++) {
 unset($array[$i]);
}

echo "Final: ".memory_get_usage()." bytes n";
/* prints
Final: 885912 bytes
*/

echo "Peak: ".memory_get_peak_usage()." bytes n";
/* prints
Peak: 13687072 bytes
*/

0