转到正文

浪淘沙

静观己心,厚积薄发

存档

分类: PHP代码片段

咱们做WEB都知道COOKIE和SESSION这对好基友。他们2个总是如影相随。大部分人也是知道如果客户端禁用COOKIE(发送request的时候不发送COOKIE或者直接unset($_COOKIE)来模拟禁用COOKIE)SESSION还是可以用了。只需要通过GET或者POST的方式传递过来SESSIONID即可。具体的做法如下:


<?php
unset($_COOKIE);//禁用cookie
$sid = isset($_REQUEST['sid']) ? $_REQUEST['sid'] :'';
if ($sid) {//如果将sessionid传递了过来,先设置sessionid 然后 开启session PS:session_id方法必须在session_start()之前调用,否则无效
session_id($sid);
}
session_start();
$sid = session_id();

if (isset($_SESSION['content'])) {
echo 'get session:',$_SESSION['content'],'<br/>';
} else {
$_SESSION['content'] = 'content';
echo 'save session<br/>';
}
echo '<a href="./session.php?sid='.$sid.'">one more</a>';

file_put_contents  这个方法顾名思义就是将一个字符串写入到指定的文件。这个方法需要注意的是:在出现并发事件的时候,file_put_contents可能会出现写入文件失败的情况。直接上测试代码。

</p>
<p>&lt;?php </p>
<p>$index = isset($_GET['index']) ? $_GET['index'] : microtime(true);<br />
$ret = file_put_contents('e:/tmp/file_put_contents.log',$index . PHP_EOL, FILE_APPEND); </p>
<p>if ($ret === false) {<br />
    echo index, ' file_put_contents failure';<br />
} else {<br />
    echo index, ' file_put_contents success';<br />
}</p>
<p>

使用 apache的ab直接做压力测试。

path-to-ab:  ab -n 1000 -c 50 http://local.test.me/file_put_contents.php

PS:意思为 总共访问http://local.test.me/file_put_contents.php这个脚本1000次,50并发同时执行。

最后的到得结果950左右行记录。 也就是说,会有50左右次写失败。

稍微修改代码,在file_put_contents 后面追加参数 LOCK_EX。最终代码如下:

</p>
<p>&lt;?php</p>
<p>$index = isset($_GET['index']) ? $_GET['index'] : microtime(true);<br />
//$ret = file_put_contents('e:/tmp/file_put_contents.log',$index . PHP_EOL, FILE_APPEND); //直接这样有失败的情况</p>
<p>$ret = file_put_contents('e:/tmp/file_put_contents.log',$index . PHP_EOL, LOCK_EX | FILE_APPEND);</p>
<p>if ($ret === false) {<br />
echo index, ' file_put_contents failure';<br />
} else {<br />
echo index, ' file_put_contents success';<br />
}</p>
<p>

再次ab压测,得出结果正常。1000次写入全部成功。

参数 LOCK_EX的意思 php manual 描述如下:Acquire an exclusive lock on the file while proceeding to the writing. (写入文件的时候,添加一个排他锁)。

 

PHP支持OOP编程,这大家都知道。但是PHP的继承和JAVA还是有点区别的。比较致命的一点就是:如果子类(ExtendsB)显示实现构造方法,那么在实例化ExtendsB的时候,系统并不会主动调用父类(ExtendsA)的构造方法

如果必须调用父类构造方法有2种方法:

1、子类(ExtendsB)中不实现构造方法(及时子类不要空实现构造方法)

2、自己手动调用父类构造方法(parent::__construct();)

直接上例子吧。

<?php
class ExtendsA {
    protected $c;

    public function ExtendsA(){
        $this->c = 10;
    }
}

class ExtendsB extends ExtendsA{
    //public function b(){} //这行解注释 就不会打印东西出来。因为ExtendsA构造没有被执行
    public function print_data(){
        echo $this->c;
    }
}

$b = new ExtendsB();
$b->print_data();

而JAVA代码就不是这样的。无论是否实现构造方法,再实例化子类的时候,系统都会递归调用父类构造方法。

public class ExtendsTestMain {

    public static void main(String args[]) {
        ExtendsTestB b = new ExtendsTestB();
        b.printData();
    }
}

class ExtendsTestA {

    protected int c;

    public ExtendsTestA() {
        c = 10;
    }
}

class ExtendsTestB extends ExtendsTestA {

    public ExtendsTestB() {

    }

    public void printData() {
        System.out.println(c);
    }
}

 

今天面试被问到一个问题。问题是这样的:“一个数组里面有正整数和负整数,对这个数组进行排序,要求,距离100比较近的排在前面。比如102距离100为2,90距离100为10,所以102排在90前面。”

这个算法很简单,下面直接给出我的程序:


function cmp($a, $b)
{
    $ta = abs(100-$a);
    $tb = abs(100-$b);
    if ($ta == $tb) {
        return 0;
    }
    return ($ta < $tb) ? -1 : 1;
}

$origin = array(
    100,0,-10,-20,-30,10,30,50,80,90,102,98
);

usort($origin, "cmp");

foreach ($origin as $key => $value) {
    echo "{$key}=>{$value}<br/>";
}

打印结果如下:


0=>100
1=>102
2=>98
3=>90
4=>120
5=>80
6=>130
7=>50
8=>30
9=>10
10=>0
11=>-10
12=>-20
13=>-30

特别喜欢PHP自带的自然排序 natsort / natcasesort。为此,还专门看了php 源码,详情请见传送门

这两天,不是太忙,就根据自己意愿用php重新实现了下,并稍微做了点修改。代码如下:

<?php

/**
 * @param $target
 * @param $destination
 *
 * @return int
 */
function strnatcmpExFoldCase0Improve($target, $destination)
{
    $return = natSortExtend($target, count($target), $destination, count($destination), 0);
    return $return;
}

function strnatcmpExFoldCase1Improve($target, $destination)
{
    return natSortExtend($target, count($target), $destination, count($destination), 1);
}

function natSortExtend($target, $targetLen, $destination, $destinationLen, $foldCase)
{
    $aend               = $targetLen;
    $bend               = $destinationLen;
    $targetLeading      = 1;//最后一次是字母或者字母后面紧跟了n个数字'0',可以跳过后面紧跟的0
    $destinationLeading = 1;//最后一次是字母或者字母后面紧跟了n个数字'0',可以跳过后面紧跟的0

    if ($targetLen == 0 || $destinationLen == 0) {
        return ($targetLen == $destinationLen ? 0 : ($targetLen > $destinationLen ? 1 : -1));
    }

    $targetIndex      = 0;
    $destinationIndex = 0;
    while (1) {
        $currentTargetItem      = $target[$targetIndex];
        $currentDestinationItem = $destination[$destinationIndex];

        /* skip over leading zeros */
        while ($targetLeading && $currentTargetItem == '0' && ($targetIndex + 1 < $aend) && ctype_digit(
                        $target[$targetIndex + 1]
                )) {
            $currentTargetItem = $target[++$targetIndex];
        }

        while ($destinationLeading && $currentDestinationItem == '0' && ($destinationIndex + 1 < $bend) && ctype_digit(
                        $destination[$destinationIndex + 1]
                )) {
            $currentDestinationItem = $destination[++$destinationIndex];
        }

        $targetLeading      = 0;
        $destinationLeading = 0;

        /* Skip consecutive whitespace */
        while (ctype_space($currentTargetItem)) {
            $currentTargetItem = $target[++$targetIndex];
        }

        while (ctype_space($currentDestinationItem)) {
            $currentDestinationItem = $destination[++$destinationIndex];
        }

        /* process run of digits */
        if (ctype_digit($currentTargetItem) && ctype_digit($currentDestinationItem)) {
            $fractional = ($currentTargetItem == '0' || $currentDestinationItem == '0');

            $ap = array_slice($target, $targetIndex);
            $bp = array_slice($destination, $destinationIndex);

            if ($fractional) {
                $result = compare_left($ap, count($ap), $bp, count($bp));
            } else {
                $result = compare_right($ap, count($ap), $bp, count($bp));
            }
            if ($result != 0) {
                return $result;
            } else if ($targetIndex == $aend && $destinationIndex == $bend) {
                /* End of the strings. Let caller sort them out. */
                return 0;
            } else {
                /* Keep on comparing from the current point. */
                $currentTargetItem      = $target[$targetIndex];
                $currentDestinationItem = $destination[$destinationIndex];
            }
        }

        if ($foldCase) {
            $currentTargetItem      = strtoupper($currentTargetItem);
            $currentDestinationItem = strtoupper($currentDestinationItem);
        }

        if ($currentTargetItem < $currentDestinationItem) {
            return -1;
        } else if ($currentTargetItem > $currentDestinationItem) {
            return +1;
        }

        $targetIndex++;
        $destinationIndex++;
        if ($targetIndex >= $aend && $destinationIndex >= $bend) {
            /* The strings compare the same.  Perhaps the caller
                will want to call strcmp to break the tie. */
            if ($aend < $bend) {
                return -1;
            } else if ($aend > $bend) {
                return 1;
            } else {
                return 0;
            }
        } else if ($targetIndex >= $aend) {
            return -1;
        } else if ($destinationIndex >= $bend) {
            return 1;
        }

        if (ctype_alpha($currentTargetItem)) {//需要处理后面的0 ,空格可以跳过
            $targetLeading = 1;
        } else if (ctype_digit($currentTargetItem) && $currentTargetItem != '0') {//非0数字 后面的0不可以跳过
            $targetLeading = 0;
        }
        if (ctype_alpha($currentDestinationItem)) {//需要处理后面的0 ,空格可以跳过
            $destinationLeading = 1;
        } else if (ctype_digit($currentDestinationItem) && $currentDestinationItem != '0') {//非0数字 后面的0不可以跳过
            $destinationLeading = 0;
        }
    }

    return 0;
}

function compare_left($a, $aend, $b, $bend)
{
    $aIndex = 0;
    $bIndex = 0;
    /* Compare two left-aligned numbers: the first to have a
       different value wins. */
    for (; ; $aIndex++, $bIndex++) {
        if ($aIndex >= count($a)) {
            echo 'warning $aIndex: ', $aIndex, ' => ', var_export($a);
            $ca = 0;
        } else {
            $ca = $a[$aIndex];//warning..
        }

        if ($bIndex >= count($b)) {
            echo 'warning $bIndex:', $bIndex, ' => ', var_export($b);
            $cb = 0;
        } else {
            $cb = $b[$bIndex];//warning..
        }

        if (($aIndex == $aend - 1 || !ctype_digit($ca)) && ($bIndex == $bend - 1 || !ctype_digit($cb))) {
            return 0;
        } else if ($aIndex == $aend - 1 || !ctype_digit($ca)) {
            return -1;
        } else if ($bIndex == $bend - 1 || !ctype_digit($cb)) {
            return +1;
        } else if ($ca < $cb) {
            return -1;
        } else if ($ca > $cb) {
            return +1;
        }
    }

    return 0;
}

function compare_right($a, $aend, $b, $bend)
{
    $aIndex = 0;
    $bIndex = 0;
    $bias   = 0;

    /* The longest run of digits wins.  That aside, the greatest
       value wins, but we can't know that it will until we've scanned
       both numbers to know that they have the same magnitude, so we
       remember it in BIAS. */
    for (; ; $aIndex++, $bIndex++) {
        if ($aIndex >= count($a)) {
            echo 'warning $aIndex: ', $aIndex, ' => ', var_export($a);
            $ca = 0;
        } else {
            $ca = $a[$aIndex];//warning..
        }

        if ($bIndex >= count($b)) {
            echo 'warning $bIndex:', $bIndex, ' => ', var_export($b);
            $cb = 0;
        } else {
            $cb = $b[$bIndex];//warning..
        }
        if (($aIndex == $aend - 1 || !ctype_digit($ca)) && ($bIndex == $bend - 1 || !ctype_digit($cb))) {
            return $bias;
        } else if ($aIndex == $aend - 1 || !ctype_digit($ca)) {
            return -1;
        } else if ($bIndex == $bend - 1 || !ctype_digit($cb)) {
            return +1;
        } else if ($ca < $cb) {
            if (!$bias) {
                $bias = -1;
            }
        } else if ($ca > $cb) {
            if (!$bias) {
                $bias = +1;
            }
        }
    }

    return 0;
}

$data = array(
        '1ab' => 'abc001',
        '2ab' => 'abc021',
        '3ab' => 'abc1',
        '4ab' => 'abc2',
        '5ab' => 'abc4',
        '6ab' => 'abc50',
        '1ae' => 'aec001',
        '2ae' => 'aec021',
        '3ae' => 'aec1',
        '4ae' => 'aec2',
        '5ae' => 'aec4',
        '6ae' => 'aec50',
        '1be' => 'bec001',
        '2be' => 'bec021',
        '3be' => 'bec1',
);

function prestrnatcmpEx2($data, $fold_case)
{
    foreach ($data as $index => $item) {
        $data[$index] = str_split($item);
    }

    if ($fold_case == 0) {
        usort($data, 'strnatcmpExFoldCase0Improve');
    } else {
        usort($data, 'strnatcmpExFoldCase1Improve');

    }

    foreach ($data as $index => $item) {
        $data[$index] = implode('', $item);
    }

    echo '<pre>';
    var_export($data);
    echo '</pre>';
}

prestrnatcmpEx2($data, 0);

$data = array(
        '1ab' => 'abc001',
        '2ab' => 'abc021',
        '3ab' => 'abc1',
        '4ab' => 'abc2',
        '5ab' => 'abc4',
        '6ab' => 'abc50',
        '1ae' => 'aec001',
        '2ae' => 'aec021',
        '3ae' => 'aec1',
        '4ae' => 'aec2',
        '5ae' => 'aec4',
        '6ae' => 'aec50',
        '1be' => 'bec001',
        '2be' => 'bec021',
        '3be' => 'bec1',
);

natsort($data);
echo '<pre>';
var_export($data);
echo '</pre>';


//输出结果
array (
  0 => 'abc1',
  1 => 'abc001',
  2 => 'abc2',
  3 => 'abc4',
  4 => 'abc021',
  5 => 'abc50',
  6 => 'aec1',
  7 => 'aec001',
  8 => 'aec2',
  9 => 'aec4',
  10 => 'aec021',
  11 => 'aec50',
  12 => 'bec1',
  13 => 'bec001',
  14 => 'bec021',
)
array (
  '1ab' => 'abc001',
  '2ab' => 'abc021',
  '3ab' => 'abc1',
  '4ab' => 'abc2',
  '5ab' => 'abc4',
  '6ab' => 'abc50',
  '1ae' => 'aec001',
  '2ae' => 'aec021',
  '3ae' => 'aec1',
  '4ae' => 'aec2',
  '5ae' => 'aec4',
  '6ae' => 'aec50',
  '1be' => 'bec001',
  '2be' => 'bec021',
  '3be' => 'bec1',
)

sscanf

(PHP 4 >= 4.0.1, PHP 5)

sscanf — Parses input from a string according to a format。

其他的就不多说了。就说下。使用sscanf format大数字的情况。


$line = '100004318055950,100';
list($uid, $expendGoldNum) = sscanf($line, '%f,%d');
echo '$uid:',$uid, '&nbsp;&nbsp;&nbsp;$expendGoldNum":',$expendGoldNum;

运行结果为:


$uid:1.0000431805595E+14      $expendGoldNum":100

逗号前面的内容直接显示为使用科学计数法表示。


$line = '100004318055950,100';
list($uid, $expendGoldNum) = sscanf($line, '%s,%d');
echo '$uid:',$uid, '&nbsp;&nbsp;&nbsp;$expendGoldNum":',$expendGoldNum;

运行结果为:


$uid:100004318055950,100   $expendGoldNum":

如果将%f修改为%s 则因为%s将所有的内容全部匹配了,不符合要求。


$line = '100004318055950,100';
list($uid, $expendGoldNum) = sscanf($line, '%[0-9],%d');
echo '$uid:',$uid, '&nbsp;&nbsp;&nbsp;$expendGoldNum":',$expendGoldNum;

运行结果为:


$uid:100004318055950   $expendGoldNum":100

这次正确了。

 

session共享一般使用的方法有两个:

1、NFS或者Samba共享的方法,让各个服务器上存放session文件的磁盘共享,这种方法简单可行。

2、集中存储到数据库中,这是比较多的实现方法,通过php提供的session_set_save_handler()函数来重定义session函数,推荐使用这种方法。

下面再对session共享问题进行稍微详细的阐述。

session共享用简单的一句话就是:“多服务器共享客户端的 SESSION ID,同时还必须共享服务器端的 SESSION 数据。

第一个目标的实现其实很简单,只需要对 COOKIE 的域(domain)进行特殊地设置即可,默认情况下,

COOKIE 的域是当前服务器的域名/IP 地址,而域不同的话,各个服务器所设置的 COOKIE 是不能相互访问

的,如 www.aaa.com 的服务器是不能读写 www.bbb.com 服务器设置的 COOKIE 的。

这里我们所说的同一网站的服务器有其特殊性,那就是他们同属于同一个一级域,如:aaa.infor96.com

和 www.infor96.com 都属于域 .infor96.com,那么我们就可以设置 COOKIE 的域为 .infor96.com,这样

aaa.infor96.com、www.infor96.com 等等都可以访问此 COOKIE。PHP 代码中的设置方法如下:

 <?php ini_set('session.cookie_domain', '.infor96.com'); ?> 

这样各个服务器共享同一客户端 SESSION ID 的目的就达到了。
继续阅读

SESSION 用百度百科的定义为:在计算机中,尤其是在网络应用中,称为“会话”。

SESSION分为客户端session和服务器端session。

当用户首次与Web服务器建立连接的时候,服务器会给用户分发一个 SessionID作为标识。SessionID是一个由24个字符组成的随机字符串。用户每次提交页面,浏览器都会把这个SessionID包含在 HTTP头中提交给Web服务器,这样Web服务器就能区分当前请求页面的是哪一个客户端。这个SessionID就是保存在客户端的,属于客户端Session。

其实客户端Session默认是以cookie的形式来存储的,所以当用户禁用了cookie的话,服务器端就得不到SessionID。这时我们可以使用url的方式来存储客户端Session。也就是将SessionID直接写在了url中,当然这种方法不常用。
我们经常说的session其实就是服务器端session。
继续阅读