编辑推荐
0

PHP将相对路径URL转换为绝对路径URL (转)

在采集程序或者蜘蛛程序中经常会遇到一类问题,就是将网页中相对路径形式的URL转换为绝对路径形式的URL。例如在http://www.msphome.cn/blog/1/这个页面中,有一个URL链接为../index.php,那么我们要将它转换为http://www.msphome.cn/blog/index.php。下面给出了解决这类问题的代码。该程序能够成功处理各种URL,将其变成绝对形式。


<?php
$a = 'http://www.abc.com/a/index.html';
$b = '../abc/a.js';
echo format_url($b, $a);

function format_url($srcurl, $baseurl) {
  $srcinfo = parse_url($srcurl);
  if(isset($srcinfo['scheme'])) {
    return $srcurl;
  }
  $baseinfo = parse_url($baseurl);
  $url = $baseinfo['scheme'].'://'.$baseinfo['host'];
  if(substr($srcinfo['path'], 0, 1) == '/') {
    $path = $srcinfo['path'];
  }else{
    $path = dirname($baseinfo['path']).'/'.$srcinfo['path'];
  }
  $rst = array();
  $path_array = explode('/', $path);
  if(!$path_array[0]) {
    $rst[] = '';
  }
  foreach ($path_array AS $key => $dir) {
    if ($dir == '..') {
      if (end($rst) == '..') {
        $rst[] = '..';
      }elseif(!array_pop($rst)) {
        $rst[] = '..';
      }
    }elseif($dir && $dir != '.') {
      $rst[] = $dir;
    }
   }
  if(!end($path_array)) {
    $rst[] = '';
  }
  $url .= implode('/', $rst);
  return str_replace('\\', '/', $url);
}

?>
0

PHP分割汉字为数组


<?php
$string ="帅朱好cc变c态啊,2!";
$arr1 = str_split_utf8($string,'gbk');
var_dump($arr1);

/**
 * 将汉字字符串分割为数组
 *
 * @param string $str
 * @param string $charset 字符编码 默认gbk
 * @return Array
 */
function str_split_utf8($str,$charset='gbk') {
    $str = iconv($charset,'utf-8',$str);
    $split=1;
    $array = array();
    for ( $i=0; $i < strlen( $str ); ){
        $value = ord($str[$i]);
        if($value > 127){
            if($value >= 192 && $value <= 223)
            $split=2;
            elseif($value >= 224 && $value <= 239)
            $split=3;
            elseif($value >= 240 && $value <= 247)
            $split=4;
        }else{
            $split=1;
        }
        $key = NULL;
        for ( $j = 0; $j < $split; $j++, $i++ ) {
            $key .= $str[$i];
        }
        array_push( $array, $key );
    }

    foreach($array as $key=>$value)
    {
        $array[$key] = iconv('utf-8',$charset,$value);
    }
    return $array;
}

 

结果:

标签: ,
1

[转]mysql_pconnect的水挺深,apache下的数据库长连接

服务器上一直用着mysql_pconnect,之前听说它会出现各种各样的问题,但服务器一直没事,也就没去管。今天看这篇文章,才知道原来mysql_pconnect有这么多的道道。

原文地址:http://www.cnblogs.com/funlake/archive/2011/09/08/2171822.html

  php的mysql持久化连接,美好的目标,却拥有糟糕的口碑,往往令人敬而远之。这到底是为啥么。近距离观察后发现,这家伙也不容易啊,要看apache的脸色,还得听mysql指挥。

  对于做为apache模块运行的php来说,要实现mysql持久化连接,首先得取决于apache这个web服务器是否支持Keep-Alive。

  Keep-Alive

  Keep-Alive是什么东西?它是http协议的一部分,让我们复习一下没有Keep-Alive的http请求,从客户在浏览器输入一个有效url地址开始,浏览器就会利用socket向url对应的web服务器发送一条tcp请求,这个请求成功一次就得需要来回握三次手才能确定,成功以后,浏览器利用socket tcp连接资源向web服务器请求http协议,发送以后就等着web服务器把http返回头和body发送回来,发回来后浏览器关闭socket连接,然后做http返回头和body的解析工作,最后呈现在浏览器上的就是漂亮的页面了。这里面有什么问题呢?tcp连接需要三次握手,也就是来回请求三次方能确定一个tcp请求是否成功,然后tcp关闭呢?来回需要4次请求才能完成!每次http请求就3次握手,4次拜拜,这来来回回的不嫌累啊,多少时间和资源都被浪费在socket连接关闭上了,能不能一次socket tcp连接发送多次http请求呢?于是Keep-Alive就应运而生,http/1.0里需要客户端自己在请求头加入Connection:Keep-alive方能实现,在这里我们只考虑http1.1了,只需要设置一下apache,让它默认就是Keep-Alive持久连接模式(apache必须1.2+才能支持Keep-Alive).在httpd.conf里找到KeepAive配置项,果断设置为On,MaxKeepAliveRequests果断为0(一个持久tcp最多允许的请求数,如果过小,很容易在tcp未过期的情况下,达到最大连接,那下次连接就又是新的tcp连接了,这里设置0表示不限制),然后对于mysql_pconnect最重要的选项KeepAliveTimeout设置为15(表示15秒).

  好了,重启apache,测试一下,赶紧写行东西

<?php
    echo "Apache进程号:".getmypid();
?>

很简单,获取当前php执行者(apache)的进程号,用浏览器浏览这个页面,看到什么?对,有看到一串进程号数字,15秒内,连续刷新页面,看看进程号有无变化?木有吧?现在把手拿开,交叉在胸前,度好时间,1秒,2秒,3,…15,16。好,过了15秒了,再去刷新页面,进程号有没有变化?变了!又是一个新的apache进程了,为什么15秒后就变成新的进程了?记得我们在apache里设置的KeepAliveTimeout吗?它的值就是15秒.现在我们应该大致清楚了,在web服务器默认打开KeepAlive的情况下,客户端第一次http成功请求后,apache不会立刻断开socket,而是一直监听来自这一客户端的请求,监听多久?根据KeepAliveTimeout选项配置的时间决定,一旦超过这一时间,apache就会断开socket了,那么下次同一客户端再次请求,apache就会新开一个进程来相应。所以我们之前15内不停的刷新页面,看到的进程号都是一致的,表明是浏览器请求给了同一个apache进程。

  浏览器是怎么知道不需要重新进行tcp连接就可以直接发送http请求呢?因为http返回头里就会带上Connection:keep-alive,Keep-alive:15两行,意思就是让客户端浏览器明白,这次socket连接我这边还没关闭呢,你可以在15内继续使用这个连接,并发送http请求,于是乎浏览器就知道应该怎么做了.

  php怎么做

  那么,php的mysql连接资源是怎么被hold住的呢,这需要查看php的mysql_pconnect的函数代码,我看了下,大概的做法就是根据当前apache进程号,生成hash key,找hash表内有无对应的连接资源,没有则推入hash表,有则直接使用。有些代码片段可以说明(具体可查看php5.3.8源码ext/mysql/php_mysql.c文件690行php_mysql_do_connect函数)

    #1.生成hash key
        user=php_get_current_user();//获取当前php执行者(apache)的进程唯一标识号
        hashed_details_length = spprintf(&hashed_details, 0, "mysql__%s_", user);//hashed_details就是hash key
    #2.如果未找到已有资源,就推入hash表,名字叫persistent_list,如果找到就直接使用
         /* try to find if we already have this link in our persistent list */
         if (zend_hash_find(&EG(persistent_list), hashed_details, hashed_details_length+1, (void **) &le)==FAILURE) {  /* we don't */
            ...
            ...
            /* hash it up(推入hash表) */
            Z_TYPE(new_le) = le_plink;
            new_le.ptr = mysql;
            if (zend_hash_update(&EG(persistent_list), hashed_details, hashed_details_length+1, (void *) &new_le, sizeof(zend_rsrc_list_entry), NULL)==FAILURE) {
                ...
                ...
            }

         }else{/* The link is in our list of persistent connections(连接已在hash表里)*/
            ...
            ...
            mysql = (php_mysql_conn *) le->ptr;//直接使用对应的sql连接资源
            ...
            ...

         }

zend_hash_find比较容易看明白,原型是zend_hash_find(hash表,key名,key长,value);如果找到,value就有值了。

      mysql的wait_timeout和interactive_timeout

  说完Keep-Alive,该到mysql家串串门了,说的是mysql_pconnect,怎么能绕开mysql的设置。

  影响mysql_pconnect最重要的两个参数就是wait_timeout和interactive_timeout,它们是什么东西?先撇一边,首先让我们把上面的代码改动一下php代码

<?php
    $conn = mysql_pconnect("localhost","root","123456") or die("Can not connect to mysql");
    echo "Mysql线程号:".mysql_thread_id($conn)."<br/>";
    echo "Apache进程号".getmypid();
?>

以上的代码没啥好解释的,让我们用浏览器浏览这个页面,看到什么?看到两个显眼的数字。一个是mysql线程号,一个是apache进程号,好了,15秒后再刷新这个页面,发现这两个id都变了,因为已经是新的apache进程了,进程id是新的,hash key就变了,php只好重新连接mysql,连接资源推入persistent list。如果15内刷新呢?apache进程肯定不变,mysql线程号会变吗?答案得问mysql了。首先这个mysql_thread_id是什么东西?shell方式登录mysql后执行命令’show processlist’,看到了什么?

mysql> show processlist;
+-----+------+-----------+------+---------+------+-------+------------------+
| Id  | User | Host      | db   | Command | Time | State | Info             |
+-----+------+-----------+------+---------+------+-------+------------------+
| 348 | root | localhost | NULL | Query   |    0 | NULL  | show processlist |
| 349 | root | localhost | NULL | Sleep   |    2 |       | NULL             |
+-----+------+-----------+------+---------+------+-------+------------------+

,发现了很重要的信息,这个processlist列表就是记录了正在跑的线程,忽略Info列为show processlist那行,那行是你当前shell登录mysql的线程。php连接mysql的线程就是Id为349那行,如果读者自己做测试,应该知道这个Id=349在你的测试环境里是另外一个值,我们把这个值和网页里输出的mysql_thread_id($conn)做做比较,对!他们是一样的。接下来最重要的是观察Command列和Time列,Command = Sleep,表明什么?表明我们mysql_pconnect连接后就一直在sleep,Time字段就告诉我们,这个线程Sleep了多久,那么Sleep了多久这个线程才能作废呢?那就是wait_timeout或者interactive_timeout要做的工作了,他们默认的值都是8小时,天啊,太久了,所以如果说web服务器关掉KeepAlive支持,那个这个processlist很容易就被撑爆,就爆出那个Too many connections的错误了,max_connectiosns配置得再多也没用。为了观察这两个参数,我们可以在mysql配置文件my.cnf里设置这两个值,找到[mysqld]节点,在里面设置多两行

interactive_timeout = 60
wait_timeout        = 30

配置完后,重启mysql,shell登录mysql,这时候show processlist可以发现只有当前线程。然后运行那个带有mysql_pconnect的php页面,再回来mysql端show processlist可发现,多了一个Commond为Sleep的线程,不停的show processlist(方向键上+enter键)观察Time列的变化2,5,10..14!,突然那个Sleep线程程被kill掉了,咋回事,还没到30秒呢,噢!忘了修改一下apache keepalive的参数了,把KeepAliveTimeOut从15改成120(只为观察,才这么改),重启apache.刷新那个页面,好,开始不停的show processlist,2..5..10..14,15,..20…26….28,29!线程被kill,这次是因为wait_timeout起了作用,浏览器那边停了30秒,30秒内如果浏览器刷新,那这个Time又会从0开始计时。这种连接不属于interactive connection(mysql shell登录那种连接就属于interactive connection),所以采用了wait_timeout的值。如果mysql_pconnect的第4个参数改改呢

<?php
$conn = mysql_pconnect('localhost','root','123456',MYSQL_CLIENT_INTERACTIVE);
echo "Mysql线程号:".mysql_thread_id($conn)."<br/>";
echo "Apache进程号:".getmypid();
?>

刷新下页面,mysql那边开始刷show processlist,这回Time > 30也不会被kill,>60才被kill了,说明设置了MYSQL_CLIENT_INTERACTIVE,就会被mysql视为interactive connection,那么这次php的mysql连接在120秒内未刷新页面的情况下,何时作废将取决于mysql的interactive_timeout的配置值。

  总结

  #1.php的mysql_pconnect要达到功效,首先必须保证apache是支持keep alive的,然后KeepAliveTimeOut应该设置多久呢,要根据自身站点的访问情况做调整,时间太短,keep alive没啥意义,时间太长,就很可能为一个闲客户端连接牺牲很多服务器资源,毕竟hold住socket监听进程是要消耗cpu内存的.

  #2.apache的KeepAliveTimeOut配置得和mysql的time out配置要有个平衡点,联系以上的观察,假设mysql_pconnect未带上第4个参数,如果apache的KeepAliveTimeOut设置的秒数比wait_timeout小,那真正对mysql_pconnect起作用的是apache而不是mysql的配置.这时如果mysql的wait_timeout偏大,并发量大的情况下,很可能就一堆废弃的connection了,mysql这边如果不及时回收,那就很可能Too many connections了.可是如果KeepAliveTimeOut太大呢,又回到之前的问题,所以貌似Apache.KeepAliveTimeOu不要太大,但比Mysql.wait_timeout 稍大,或者相等是比较好的方案,这样可以保证keep alive过期后,废弃的mysql连接可以及时被回收. 

  后记

  Pdo数据库的长连接机制是否和mysql_pconnect一样?经过试验观察和源码探究,发现也是一样的处理方式。

0

GODADDY .net续费优惠码

SCAM14

0

[转]网站优化 更小的静态资源

更小的静态资源(js、css、png、gif),意味着更少的网络传送时间。构建的时候,可以把这些静态资源进行压缩优化(不像gzip/deflate压缩),使之更小化。有很多相应的开源工具帮助你完成这项工作。

javascript

  • Google Closure Compiler
  • UglifyJS
  • YUI Compressor
  • ShrinkSafe
  • 其它,比如JSMIN

Node.js、jQuery1.5开始使用UglifyJS,UglifyJS压缩比YUI Compressor更小、比Google Closure Compiler更安全。尽管如此,但UglifyJS需要部署NodeJS环境,所以我们还是选择使用Google Closure Compiler

style(css)

  • CSSTidy
  • YUI Compressor
  • Yslow/Google Page Speed

CSSTidy和YUI Compressor都很棒,我们还是选择老牌的YUI Compressor,因为我们更熟悉它,它也能够满足我们的需求。

png8/gif图片

  • Optipng
  • AdvanceCOMP(advpng、advdef)
  • ImageMagic(mogrify、identify、convert)
  • Pngcrush
  • Pngout
  • gifsicle
  • jpegtran

任何大一点的网站页面都会使用到不少图片,压缩优化图片很有必要。选择什么样的图片格式,决定了怎么去压缩图片。一般而言,只要是非动画图片,我们 推荐png8,即便是颜色很少的小图片(尽管这样的图片gif有更高压缩性,但应该使用css sprites)。Pngout没有开放源码,仅能在Window NT平台使用,所以我们并不考滤使它。Pngcrush虽然很好用,但是optipng、advpng以及advdef结合使用能把图片压缩得更小,所以 我们选择optipng、advpng以及advdef压缩优化PNG图片。 Optipng压缩优化图片、而advdef则优化压缩算法。

构建脚本

发布产品的时候,我们希望构建前端资源,包括压缩优化、合并等等。构建应该尽量满足:
1.整个过程是自动的,不需要人工介入
2.所有的操作都是安全的
3.免费的命令行工具

我们这里应用bash写了一个简版的部署脚本,能够简单地应付中小型网站静态资源发布。

#!/bin/sh
#filename:build.sh
IN_FILE="/var/www.imgwell.com/themes/ocean/misc"
OUT_FILE="/var/www.imgwell.com/misc"
EXCLUDE_FILES="jquery.min.js LAB.min.js"
GOOGLE_COMPILER="/opt/build/bin/compiler.jar"
YUI_COMPRESSOR="/opt/build/bin/yuicompressor-2.4.6.jar"
OPTIPNG="/usr/local/bin/optipng -quiet -o3 "
ADVPNG="/usr/local/bin/advpng -q -z -4 "
ADVDEF="/usr/local/bin/advdef -q -z -4 "

function mt_ver_code() {
    local MATRIX="23456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnpqrstuvwxyz"
    local LENGTH=12
    while [ "${n:=1}" -le "$LENGTH" ]; do
        local PASS="$PASS${MATRIX:$(($RANDOM%${#MATRIX})):1}"
        let n+=1
    done
    echo -n ${PASS}
}

function mt_file_ext() {
    local FILE=`basename -- "$1"`
    echo -n "${FILE##*.}"
}

function mt_file_size() {
    if [ -f "$1" ]; then
        echo -n `ls -l -- "$1" |awk '{print $5}'`
    else
        echo -n 0
    fi
}

function mt_has_exclude() {
    if [ -z "$EXCLUDE_FILES" ]; then
        echo -n 0
        return 0
    fi
    echo "$EXCLUDE_FILES" |grep -q -w -- "${1}"
    if [ $? -eq 0 ]; then
        echo -n "1"
    else
        echo -n "0"
    fi
}

function mt_google_compile() {
    java -jar "$GOOGLE_COMPILER" --js $1 --js_output_file $2
}

function mt_yui_compressor() {
    java -jar "$YUI_COMPRESSOR" $1 -o $2 --charset utf-8
}

function mt_png_opti() {
    [ -f "`echo ${OPTIPNG} |awk '{print $1}'`" ] && ${OPTIPNG} "${1}"
    [ -f "`echo ${ADVPNG} |awk '{print $1}'`" ] && ${ADVPNG} "${1}"
    [ -f "`echo ${ADVDEF} |awk '{print $1}'`" ] && ${ADVDEF} "${1}"
}

function __main__() {
    [ -d "$IN_FILE" ] || exit 1
    local VER_CODE=`mt_ver_code`
    local FILE_STATUS="!"
    mkdir -p "${OUT_FILE}/${VER_CODE}"

    for f in `ls -1 "$IN_FILE"`; do
        if [ -d "${IN_FILE}/${f}" ] ; then
            continue
        fi

        local HAS_EXCLUDE=`mt_has_exclude "${f}"`
        local FILE_SRC_SIZE=`mt_file_size "${IN_FILE}/${f}"`

        if [ "`mt_file_ext "${f}"`" = "js" -a "$HAS_EXCLUDE" = "0" ]; then
            mt_google_compile "${IN_FILE}/${f}" "${OUT_FILE}/${VER_CODE}/${f}"
            FILE_STATUS="G"
        elif [ "`mt_file_ext "${f}"`" = "css" -a "$HAS_EXCLUDE" = "0"  ]; then
            mt_yui_compressor "${IN_FILE}/${f}" "${OUT_FILE}/${VER_CODE}/${f}"
            FILE_STATUS="Y"
        elif [ "`mt_file_ext "${f}"`" = "png" -a "$HAS_EXCLUDE" = "0" ]; then
            cp "${IN_FILE}/${f}" "${OUT_FILE}/${VER_CODE}"
            [ -f "${OUT_FILE}/${VER_CODE}/${f}" ] && {
                mt_png_opti "${OUT_FILE}/${VER_CODE}/${f}"
                FILE_STATUS='O'
            }
        else
            cp "${IN_FILE}/${f}" "${OUT_FILE}/${VER_CODE}"
            if [ $? -eq 0 ]; then
                FILE_STATUS="-"
            else
                FILE_STATUS="D"
            fi
        fi

        local FILE_DST_SIZE=`mt_file_size "${OUT_FILE}/${VER_CODE}/${f}"`
        echo "${FILE_STATUS} ${HAS_EXCLUDE} ${f} ${FILE_SRC_SIZE}/${FILE_DST_SIZE}"
    done
    echo "===========/" $VER_CODE "\=========="
}

__main__

执行结果如下

[root@www-avatar misc]# ./build.sh
O 0 6N9FQPpTHCy.png 820/258
Y 0 base.css 40171/35530
O 0 FSEB6oLTK3I.png 10362/10362
- 0 GsNJNwuI-UM.gif 522/522
O 0 heart.png 921/807
O 0 IJYgcESal33.png 5771/5771
O 0 _IKHHfAgFQe.png 2635/2302
G 0 jquery.elastic.js 4988/1665
- 1 jquery.min.js 85260/85260
G 0 jquery.ui.dialog.js 10074/5274
G 0 jquery.ui.pview.js 4565/2878
- 1 LAB.min.js 5537/5537
O 0 lFahQXTaTNO.png 90/90
G 0 mutfa.js 36958/21777
O 0 nCItFQafRu8.png 452/288
O 0 p13yZ069LVL.png 792/219
- 0 plupload.flash.swf 18537/18537
G 0 plupload.full.js 48277/46682
Y 0 position.css 7737/7440
O 0 star.png 3292/283
G 0 stars.js 6333/2622
Y 0 ui_plugin.css 12794/12079
G 0 up.js 6230/3991
- 0 uVR6w3wRHEJ.gif 54/54
O 0 WSQ2wnhSG-F.png 245/229
- 0 _ZWZupdaAgS.gif 827/827
===========/ LruQcmx4Zi84 \==========

总结

1.UglifyJS压缩比YUI Compressor更小,比Google Closure Compiler更安全。不想冒险,还是应该选择UglifyJS。若想最小化,可以选择Google Closure Compiler
2.YUI Compressor压缩css文件。但CSSTidy也很不错
3.optipng -o3 *.png |advpng -z -4 *.png |advdef -z -4 *.png 将最大化压缩优化png图片
4.网页尽量使用png格式图片,并且压缩优化它,使之最优

 

 

原文地址:http://www.perfgeeks.com/?p=660

1

一键启用firebug-lite调试程序

习惯在firebox下用firebug调试程序,用IE的开发者工具有点不习惯。还好firebug提供lite版本,可以直接在页面中嵌入

<script type="text/javascript" src="https://getfirebug.com/firebug-lite-debug.js"></script>

进行调试。

但是但是但是,每次调试都要往页面中嵌入这样一段JS,然后保存,然后刷新,然后XXXX,毕竟很麻烦。

介绍一种简单的方法:

在浏览器(包括IE或其它任何的浏览器)中,收藏下面的网址

javascript:void((function(){var%20e=document.createElement("script");e.onload=e.onreadystatechange=function(){};document.body.appendChild(e);e.setAttribute("src","https://getfirebug.com/firebug-lite-debug.js");})())

(注意把里面的全角引号改成半角,万恶的wordpress编辑器,我治不了了,老是自动把半角引号改为全角)

在你需要调试的页面,直接点击收藏夹中的该链接,就可以启动firebug-lite。so easy……

上面firebug官方提供的JS地址(https://getfirebug.com/firebug-lite.js)有点慢,点击后需要十几秒才能加载完,所以点一下后要耐心等待。也可以自行下载JS到本地,然后把路径改为自己的地址即可。