| 软件名 | 版本号 | 理由 |
|---|---|---|
| gearmand | 0.18 | 再往上的版本,对c++ boost库要求>1.39,Centos 5.7不支持 |
| memcached | 1.4.13 | 可以使用最新版本 |
| libmemcached | 0.53 | 0.53 release from the 1.0 series released |
| scws | 1.2.0 | 最新版本 |
| xcache | 2.0.0 | 最新版本 |
| gearman | 0.8.1 | php扩展,只能用此系列的最后版本号,否则libgearman>0.21 |
| memcached | 2.0.1 | php扩展,只能上最新版本,否则不兼容php5.4 |
| memcache | 3.0.6 | php扩展,只能用最新的beta版本,否则不兼容php5.4 |
#!/bin/sh _server_root="/opt/php" PEAR_INSTALLDIR=/usr/share/pear export PEAR_INSTALLDIR phpconfig="--prefix=$_server_root \ --with-layout=GNU \ --disable-debug \ --enable-ftp \ --enable-inline-optimization \ --enable-magic-quotes \ --enable-mbstring \ --enable-mm=shared \ --enable-safe-mode \ --enable-trans-sid \ --enable-xml \ --with-dom \ --with-curl \ --with-xsl \ --with-jpeg-dir \ --with-png-dir \ --with-tiff-dir \ --with-zlib-dir \ --with-gettext \ --with-regex=system \ --with-xml \ --enable-bcmath \ --with-gd=shared \ --with-freetype-dir \ --enable-gd-native-ttf \ --without-pdo-sqlite \ --without-sqlite \ --without-ldap \ --without-ldap-sasl \ --enable-pcntl \ --enable-sockets \ --with-mcrypt \ --enable-soap \ --enable-libxml \ --with-mysql=mysqlnd \ --with-mysqli=mysqlnd \ --with-pdo-mysql=mysqlnd \ --enable-zip \ --enable-fastcgi \ --enable-cgi \ --enable-discard-path \ --enable-force-cgi-redirect \ --enable-cli \ --enable-fpm \ --with-fpm-user=nobody \ --with-fpm-group=nobody \ --with-libevent \ " ./configure $phpconfig
变化不大,格式从xml转变成ini格式
short_open_tag = On max_execution_time = 90 max_input_time = 120 max_input_vars = 300 memory_limit = 128M error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT display_errors = Off post_max_size = 8M extension_dir = "/opt/php/lib/" extension="gd.so" extension="xcache.so" extension="scws.so" extension="gearman.so" extension="memcache.so" extension="memcached.so" ;extension="zip.so" ;extension="pdo_mysql.so" ;extension="geoip.so" ;extension="mongo.so" ;zend_extension="/opt/php/lib/ZendOptimizer.so" cgi.force_redirect = 0 cgi.fix_pathinfo = 0 file_uploads = On upload_max_filesize = 8M max_file_uploads = 5 allow_url_fopen = Off allow_url_include = Off date.timezone = Asia/Shanghai session.name = YGXSID [xcache.admin] xcache.admin.enable_auth = On xcache.admin.user = "admin" ; Change xcache.admin.pass to the MD5 fingerprint of your password ; Use md5 -s "your_secret_password" to find the fingerprint xcache.admin.pass = "0d6790ac6338e89139ff37a1ef3bc97a" [xcache] xcache.shm_scheme = "mmap" xcache.size = 32M xcache.count = 8 xcache.slots = 8K xcache.ttl = 0 xcache.gc_interval = 0 xcache.var_size = 32M xcache.var_count = 1 xcache.var_slots = 8K xcache.var_ttl = 0 xcache.var_maxttl = 0 xcache.var_gc_interval = 0 xcache.test = Off xcache.readonly_protection = Off xcache.mmap_path = "zero" xcache.coredump_directory = "" xcache.cacher = Off xcache.stat = Off xcache.optimizer = Off [xcache.coverager] xcache.coverager = Off xcache.coveragedump_directory = ""
include_path = ".:/home/html/publiclib"
因为使用include_path和相对路径的情况下, 性能会和寻找的次数有关,所以, 在能使用绝对路径的情况下最好使用绝对路径.
在模块化的系统设计中, 一般应该在模块内, 通过获取模块的部署路径(dirname(FILE), php5.3以后更是提供了DIR常量)从而使用绝对路径.
#php_fpm_BIN=/opt/php/bin/php-cgi php_fpm_BIN=/opt/php/sbin/php-fpm php_fpm_CONF=/opt/php/etc/php-fpm.conf php_opts="--fpm-config $php_fpm_CONF" #$php_fpm_BIN --fpm $php_opts $php_fpm_BIN $php_opts
my.cnf
old_passwords=0 mysql>update user set Password=PASSWORD('secret'); mysql>flush privileges;
PHP 5.4 Call-time pass-by-reference
// Right way! function myFunc(&$arg) { } myFunc($var); // Wrong way! function myFunc($arg) { } myFunc(&$arg);
php_network_getaddresses: getaddrinfo failed: Name or service not known in /hom/html/publiclib/Library/class/memcache.class.php on line 22
if ($noreplace == ""){ //while (ereg ('{([a-zA-Z0-9_-]+)}', $sql, $regs)) { while (preg_match ('/{([a-zA-Z0-9_-]+)}/', $sql, $regs)) { $found = $regs[1]; //$sql = ereg_replace("\{".$found."\}",$this->db_prefix.$found, $sql); $sql = preg_replace("/\{".$found."\}/",$this->db_prefix.$found, $sql); } }
PHP4.2以上版本不需要用session_register()注册,直接可以使用$_SESSION变量 //session_register("valicode");
foreach($records->records as $q) ==》 foreach ($records->records as $k => $q)
作为一个充满激情的开发人员,我很高兴地见证了PHP这个广受赞誉的服务器端脚本语言在过去二十年中的发展。
PHP 8.x系列始于2020年11月26日发布的PHP 8.0,随后是2021年11月25日发布的PHP 8.1。这些版本引入了几个突破性的功能,以及实质性的性能改进,对Web开发环境产生了积极的影响。
PHP 8.0中值得注意的特性包括
PHP 8.1继续构建在PHP 8.0奠定的坚实基础上,引入了新的特性,如
PHP 8.2引入了许多新特性,包括:
./configure --prefix=/opt/php8310 --enable-mbstring=shared --enable-fpm --with-fpm-systemd \ --with-openssl --with-zlib --with-bz2 --enable-gd --with-jpeg --enable-intl
参考资料: http://php.net/manual/en/security.database.sql-injection.php
<?php class secure { function secureSuperGlobalGET(&$value, $key) { $_GET[$key] = htmlspecialchars(stripslashes($_GET[$key])); $_GET[$key] = str_ireplace("script", "blocked", $_GET[$key]); $_GET[$key] = mysql_escape_string($_GET[$key]); return $_GET[$key]; } function secureSuperGlobalPOST(&$value, $key) { $_POST[$key] = htmlspecialchars(stripslashes($_POST[$key])); $_POST[$key] = str_ireplace("script", "blocked", $_POST[$key]); $_POST[$key] = mysql_escape_string($_POST[$key]); return $_POST[$key]; } function secureGlobals() { array_walk($_GET, array($this, 'secureSuperGlobalGET')); array_walk($_POST, array($this, 'secureSuperGlobalPOST')); } } ?>
过下准备写个股票机械交易系统,先搞掂数据采集这部分先,做了个用php从yahoo获取股票数据的例子, 运行在shell下,其实php做shell几好用的.
以下为源代码:
gupiao.php , 获取600808马钢股份的数据.
<?php include “Snoopy.class.inc”; $url=”http://finance.cn.yahoo.com/q?s=600808.ss”; $snoopy = new Snoopy; $snoopy->agent = “Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)”; $snoopy->fetch($url); $getstr=$snoopy->results; $getstr=trim($getstr); if($getstr==”") { print “No Data”; print “\n”; exit; } $str=mycut(”<span id=\”top_date\”>”,”<div class=\”ft\”>”,$getstr); $pieces = explode(”</span>”, $str); $ftime=$pieces[0]; $ftime=trim($ftime); print “时间: “.$ftime; print “\n”; $stra=mycut(”最新价:”,”</”,$str); $stra=$stra.”</”; //print $stra; $stra=mycut(”>”,”</”,$stra); print “最新价: “.$stra; print “\n”; $strb=mycut(”今开盘:”,”</”,$str); $strb=$strb.”</”; $strb=mycut(”>”,”</”,$strb); print “开盘价: “.$strb; print “\n”; $strc=mycut(”最高价:”,”</”,$str); $strc=$strc.”</”; $strc=mycut(”>”,”</”,$strc); print “最高价: “.$strc; print “\n”; $strd=mycut(”最低价:”,”</li>”,$str); $strd=mycut(”>”,”</”,$strd); print “最低价: “.$strd; print “\n”; $stre=mycut(”前收盘:”,”</”,$str); $stre=$stre.”</”; $stre=mycut(”>”,”</”,$stre); print “前收盘: “.$stre; print “\n”; function mycut($firststr,$laststr,$srcstr) { // $findstr=”"; $pos1 = strpos($srcstr, $firststr); if ($pos1 === false) { return “”; } //print “pos1: “.$pos1.”\n”; $pos2 = strpos($srcstr, $laststr, $pos1); if ($pos2 === false) { return “”; } if ($pos2<$pos1) { return “”; } //print “pos2: “.$pos2.”\n”; // $num=1; $message=explode($firststr,$srcstr); $message=explode($laststr,$message[1]); return $message[0]; } ?>
还是用到php的Snoopy类, 在shell状态下输入php -q gupiao.php就可以执行,当然也可以运行在web下.
sharetronix是一个开源的php微博系统,其功能之完善令人叫绝,最基本的发微博、转发、评论、好友关注、微博内嵌图片、视频、音乐等自 然不在话下,甚至群组、权限管理、多语言,移动设备访问都一应俱全,而且部署安装过程非常简单,即使不做任何修改,安装之后即刻就能上线一个“五脏俱全” 的微博平台。
server { listen 80; server_name weibo.152153.com; root /usr/yupoo/app/sharetronix.3.1.1; if ( -d $request_filename ){ rewrite (.*) $1/index.php break; } if (-f $request_filename) { break; } location / { try_files $uri /index.php?$args; } location ~ .*\.(php|php5)?$ { fastcgi_pass 9900.php.com; include common/fastcgi_params; } location ~ .*\.(js|css|gif|jpg|jpeg|png|bmp|swf|html|htm|xml|txt|ico|cur|crx|xpi)$ { expires 7d; access_log off; } access_log /usr/yupoo/logs/sharetronix.3.1.1/access.log main; error_log /usr/yupoo/logs/sharetronix.3.1.1/error.log; }
一台服务器流量比较大,因为程序的需要,session的过期时间设置的是3小时,导致/tmp下堆积了近20万的session文件。进而导致内核占用的cpu急剧上升。因为session的读写涉及到大量小文件的随机读写,并且是集中在一个目录下,iowait也急剧升高。
最简单的办法莫过于将/tmp挂载为 tmpfs文件系统,也就是内存中。
php本身支持session的多级散列
在php.ini中,将
;session.save_path = /tmp
改为
session.save_path = "2;/tmp/session"
表示将session存储到 /tmp/session这个文件夹中,并且是用2及散列。保存退出,等第三步结束后重启php
php并不会自动去创建这些文件夹,不过在源文件中提供了一些创建文件夹的脚本。下面这个脚本也好用
#!/bin/sh I="0 1 2 3 4 5 6 7 8 9 a b c d e f" for acm in $I;do for x in $I;do mkdir -p /tmp/session/$acm/$x done done chown -R nobody:nobody /tmp/session chmod -R 1777 /tmp/session
因为/tmp是用的内存,服务器重启后,里面的所有文件都会丢失,所以,需要把上面的脚本加入到 /etc/rc.local中,并且要放在启动php之前
session在经过session.gc_maxlifetime后会过期,但并不会马上被删除,时间长了以后会造成/tmp空间占用很大。具体的删除算法懒得去研究。
下面这个命令可以删除过期的session,我这里定义的过期时间是3小时
find /tmp/session -amin +180 -exec rm -rf {} \;
放入cron中,10分钟执行一次,完事。
有时候我们需要动态加载一个模块,最简单的方法可以如下操作,以mime_magic模块为例:
cd php-4.4.4/ext/mime_magic/ /usr/local/bin/phpize ./configure –with-mime-magic –with-php-config=/usr/local/bin/php-config make -j 16 make install
接着修改php.ini,将原先的:
extension_dir = “./”
去掉,换成如下的:
extension_dir = “/usr/local/lib/php/extensions/no-debug-non-zts-20020429/”
并加上:
extension=mime_magic.so
最后重起apache即可,简单吧:)
PHP5.2.4之前的版本无需设置时区。下面是修改PHP时区的三个办法。
找到date.timezone这行,去掉前面的分号,改成:
date.timezone = Asia/Shanghai
修改.htaccess文件有两种办法,下面的两条语句只要有一条即可
php_value date.timezone Asia/Shanghai SetEnv TZ Asia/Shanghai
也是下面的两条语句只要其中的一句即可
date_default_timezone_set('Asia/Shanghai'); ini_set('date.timezone','Asia/Shanghai');
;;;;;;;;;;;;;;;; ; File Uploads ; ;;;;;;;;;;;;;;;; ; Whether to allow HTTP file uploads. file_uploads = On ; Temporary directory for HTTP uploaded files (will use system default if not ; specified). ;upload_tmp_dir = ; Maximum allowed size for uploaded files. upload_max_filesize = 80M ;;;;;;;;;;;;;;;;;;; ; Resource Limits ; ;;;;;;;;;;;;;;;;;;; max_execution_time = 3600; Maximum execution time of each script, in seconds max_input_time = 3600; Maximum amount of time each script may spend parsing request data memory_limit = 100M ; Maximum amount of memory a script may consume (8MB) ; Maximum size of POST data that PHP will accept. post_max_size = 80M
uploadmaxfilesize: 这是上传单一档案的大小限制,譬如我若允许上传超过20MB的影片档,那这数值就必须至少大于「20M」才可以。
postmaxsize: PHP允许一次上传档案的大小限制,若我一次要上传2个15MB的影片档,那麽这个数值就必须至少大于「30M」了。
memory_limit: 执行每个scripts时使用的memory大小限制
这三个数值的大小,根据php官方manual的要求,必须是 memorylimit > postmaxsize > uploadmax_filesize
使用 mysql_real_escape_string() 防止 SQL 注入问题。 使用正则表达式过滤字符串 和 strlen() 来确保 GET 数据未被篡改。 使用正则表达式过滤字符串 和 strlen() 来确保用户提交的数据不会使内存缓冲区溢出。 使用 strip_tags() 和 htmlspecialchars() 防止用户提交可能有害的 HTML 标记。 避免系统被 Tamper Data 这样的工具突破。 重写功能,使用更安全的专用表单处理函数,避免使用隐藏表单变量。 使用 md5() 或其他加密机制对隐藏表单变量中的表名或其他敏感信息进行加密。在 PHP 端不要忘记对它们进行解密。 通过使用缩写或昵称让值的含义模糊,在 PHP 表单处理函数中再对这些值进行转换。例如,如果要引用 users 表,可以用 u 或任意字符串(比如 u8y90x0jkL)来引用它。 使用惟一的令牌防止用户向服务器远程提交表单。
open_basedir可将用户访问文件的活动范围限制在指定的区域,通常是其家目录的路径,也可用符号“.”来代表当前目录。
注意用open_basedir指定的限制实际上是前缀,而不是目录名。
若"open_basedir = /dir/user", 那么目录 "/dir/user" 和 "/dir/user1"都是可以访问的。
"open_basedir = /dir/user/"
openbasedir也可以同时设置多个目录, 在Windows中用分号分隔目录,在任何其它系统中用冒号分隔目录。当其作用于Apache模块时,父目录中的openbasedir路径自动被继承。
disable_functions = system,passthru,shell_exec,exec, proc_open,popen
二者选一即可,也可都选
在php.ini中的
disable_functions= passthru,exec,shell_exec,system
后面加上php处理文件的函数,主要有
fopen,mkdir,rmdir,chmod,unlink,dir fopen,fread,fclose,fwrite,file_exists closedir,is_dir,readdir.opendir fileperms.copy,unlink,delfile
即成为
disable_functions=passthru,exec,shell_exec,system,fopen,mkdir,rmdir,chmod,unlink,dir,fopen,fread,fclose,fwrite,file_exists,closedir,is_dir,readdir.opendir,fileperms.copy,unlink,delfile
ok,大功告成,php木马拿我们没辙了,
遗憾的是这样的话,利用文本数据库的那些东西就都不能用了。
参考资料: http://php.net/manual/en/security.database.sql-injection.php
<?php class secure { function secureSuperGlobalGET(&$value, $key) { $_GET[$key] = htmlspecialchars(stripslashes($_GET[$key])); $_GET[$key] = str_ireplace("script", "blocked", $_GET[$key]); $_GET[$key] = mysql_escape_string($_GET[$key]); return $_GET[$key]; } function secureSuperGlobalPOST(&$value, $key) { $_POST[$key] = htmlspecialchars(stripslashes($_POST[$key])); $_POST[$key] = str_ireplace("script", "blocked", $_POST[$key]); $_POST[$key] = mysql_escape_string($_POST[$key]); return $_POST[$key]; } function secureGlobals() { array_walk($_GET, array($this, 'secureSuperGlobalGET')); array_walk($_POST, array($this, 'secureSuperGlobalPOST')); } } ?>
Green for Mars!
John R. Doe
The idea of little green men from Mars, long a staple of science fiction, may soon turn out to be less fantasy and more fact. Recent samples sent by the latest Mars exploration team indicate a high presence of chlorophyll in the atmosphere. Chlorophyll, you will recall, is what makes plants green. It’s quite likely, therefore, that organisms on Mars will have, through continued exposure to the green stuff, developed a greenish tinge on their outer exoskeleton.
An interview with Dr. Rushel Bunter, the head of ASDA’s Mars Colonization Project blah blah…
What does this mean for you? Well, it means blah blahblah…
相当标准的文本:
它有一个标题、一个署名和很多段的文字。把这篇文档转换成为HTML真正需要做的是使用HTML的分行和分段标记把原文的布局保留在Web页面上。特殊的标点符号需要被转换成为对应的HTML符号,超链接需要变得可以点击。
下面的PHP代码就会完成上面所有的任务:
<?php // set source file name and path $source = "toi200686.txt"; // read raw text as array $raw = file($source) or die("Cannot read file"); // retrieve first and second lines (title and author) $slug = array_shift($raw); $byline = array_shift($raw); // join remaining data into string $data = join('', $raw); // replace special characters with HTML entities // replace line breaks with <br /> $html = nl2br(htmlspecialchars($data)); // replace multiple spaces with single spaces $html = preg_replace('/ss+/', ' ', $html); // replace URLs with <a href...> elements $html = preg_replace('/s(w+://)(S+)/', ' <a href="12" target="_blank">12</a>', $html); // start building output page // add page header $output =<<< HEADER <html> <head> <style> .slug {font-size: 15pt; font-weight: bold} .byline { font-style: italic } </style> </head> <body> HEADER; // add page content $output .= "<div class='slug'>$slug</div>"; $output .= "<div class='byline'>By $byline</div><p />"; $output .= "<div>$html</div>"; // add page footer $output .=<<< FOOTER </body> </html> FOOTER; // display in browser echo $output; // AND/OR // write output to a new .html file file_put_contents(basename($source, substr($source, strpos($source, '.'))) . ".html", $output) or die("Cannot write file"); ?>
/** * @param string $string 原文或者密文 * @param string $operation 操作(ENCODE | DECODE), 默认为 DECODE * @param string $key 密钥 * @param int $expiry 密文有效期, 加密时候有效, 单位 秒,0 为永久有效 * @return string 处理后的 原文或者 经过 base64_encode 处理后的密文 * * @example * * $a = authcode('abc', 'ENCODE', 'key'); * $b = authcode($a, 'DECODE', 'key'); // $b(abc) * * $a = authcode('abc', 'ENCODE', 'key', 3600); * $b = authcode('abc', 'DECODE', 'key'); // 在一个小时内,$b(abc),否则 $b 为空 */ function authcode($string, $operation = 'DECODE', $key = '', $expiry = 3600) { $ckey_length = 4; // 随机密钥长度 取值 0-32; // 加入随机密钥,可以令密文无任何规律,即便是原文和密钥完全相同,加密结果也会每次不同,增大破解难度。 // 取值越大,密文变动规律越大,密文变化 = 16 的 $ckey_length 次方 // 当此值为 0 时,则不产生随机密钥 $key = md5($key ? $key : 'default_key'); //这里可以填写默认key值 $keya = md5(substr($key, 0, 16)); $keyb = md5(substr($key, 16, 16)); $keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : ''; $cryptkey = $keya.md5($keya.$keyc); $key_length = strlen($cryptkey); $string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string; $string_length = strlen($string); $result = ''; $box = range(0, 255); $rndkey = array(); for($i = 0; $i <= 255; $i++) { $rndkey[$i] = ord($cryptkey[$i % $key_length]); } for($j = $i = 0; $i < 256; $i++) { $j = ($j + $box[$i] + $rndkey[$i]) % 256; $tmp = $box[$i]; $box[$i] = $box[$j]; $box[$j] = $tmp; } for($a = $j = $i = 0; $i < $string_length; $i++) { $a = ($a + 1) % 256; $j = ($j + $box[$a]) % 256; $tmp = $box[$a]; $box[$a] = $box[$j]; $box[$j] = $tmp; $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256])); } if($operation == 'DECODE') { if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) { return substr($result, 26); } else { return ''; } } else { return $keyc.str_replace('=', '', base64_encode($result)); } } $a = authcode('abc', 'ENCODE', 'key'); $b = authcode($a, 'DECODE', 'key'); // $b(abc) echo $a."\n"; echo $b."\n";
为了方便做seo用的, 把内页的关键字替换带链接的关键词指向首页,所以不能全替换,只替换一次:
php原来的str_replace函数是替换全部的,不能用,所以在网上找高人已写好的。
function str_replace_once($needle, $replace, $haystack) { $pos = strpos($haystack, $needle); if ($pos === false) { return $haystack; } return substr_replace($haystack, $replace, $pos, strlen($needle)); }
最后的就是应用效果不错.
以前总是自己用php代码模拟浏览器,总是写不好,当然我这种非专业出身就是学不好.
最近在写一个抓取Amazon商品php代码时,无意中从搜索引擎搜到的.那个Snoopy这个类实在太好用了, 记录一下怎样使用.
snoopy是一个php类,用来模仿web浏览器的功能,它能完成获取网页内容和发送表单的任务。
方便抓取网页的内容 方便抓取网页的文字(去掉HTML代码) 方便抓取网页的链接 支持代理主机 支持基本的用户/密码认证模式 支持自定义用户agent,referer,cookies和header内容 支持浏览器转向,并能控制转向深度 能把网页中的链接扩展成高质量的url(默认) 方便提交数据并且获取返回值 支持跟踪HTML框架(v0.92增加) 支持再转向的时候传递cookies
<?php include “Snoopy.class.php”; $snoopy = new Snoopy; $snoopy->fetch(“http://www.lpfrx.com”); echo $snoopy->results; ?>
<?php include “Snoopy.class.php”; $snoopy = new Snoopy; $snoopy->fetchtext(“http://www.lpfrx.com”); echo $snoopy->results; ?>
<?php include “Snoopy.class.php”; $snoopy = new Snoopy; $snoopy->fetchlinks(“http://www.lpfrx.com”); print_r($snoopy->results);
原来之前做的php抓取RSS里的MagpieRSS类也用到了,以后可以Snoopy做抓取,应该说采集时就爽了.
SIGSEGV信号一般表示
SIGSEGV --- Segment Fault. The possible cases of your encountering this error are: 1.buffer overflow --- usually caused by a pointer reference out of range. 2.stack overflow --- please keep in mind that the default stack size is 8192K. 3.illegal file access --- file operations are forbidden on our judge system
其中的第三条,跟本问题的关系比较大。也就是php-cgi访问了一个不存在的或者没有权限访问的文件
我用的php-fpm补丁是0.5.8版的,按照一些说法,只要设置了
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
之后,php-cgi如果找不到文件或者没有权限访问的话 会提示No input file specified. 或者Access denied.
问题到这里似乎又陷入了僵局
后来又在php.ini中找到了php-cgi的一个参数 cgi.fix_pathinfo
cgi.fix_pathinfo boolean
对 CGI 提供了真正的 PATHINFO/PATHTRANSLATED 支持。
以前 PHP 的行为是将 PATHTRANSLATED 设为 SCRIPTFILENAME,而不管 PATH_INFO 是什么。
将此值设为 1 将使 PHP CGI 修正其路径以遵守规格。设为 0 将使 PHP 的行为和从前一样。默认为零。用户应该修正其脚本使用 SCRIPTFILENAME 而不是PATHTRANSLATED。
把这个参数的值设置为1 ,cgi会多做一些检查,来判断请求的路径中,那部分是文件名,哪部分是路径名
下面是google groups上的一段话
when cgi.fixpathinfo was set to “1” it caused a lot of checks in order to find which part of SCRIPTFILENAME is a file name and which is PATHINFO. In case of missing file it caused NULL in pathtranslated, which caused the crash.
由于网站首页以及vTigerCRM里经常在截取中文字符串时出现乱码(使用substr),今天找到一个比较好的截取中文字符串方法,在此与大家共享。
function msubstr($str, $start, $len) { $tmpstr = ""; $strlen = $start + $len; for($i = 0; $i < $strlen; $i++) { if(ord(substr($str, $i, 1)) > 0xa0) { $tmpstr .= substr($str, $i, 2); $i++; } else $tmpstr .= substr($str, $i, 1); } return $tmpstr; }
例如用户点击删除文章按钮后,控制器调用操作文章的模型,删除掉指定文章,最后通过视图显示成功删除文章的提示信息。
一个业务逻辑在模型中实现,而处理结果在视图中呈现。控制器则充当中间人,根据用户请求调用模型,然后把处理结果传递给视图。
在处理一个请求的过程中
同一用户的所有会话 适合存放和当前用户相关的数据
php或webserver的进程 在进程结束前有效
限定在当前机器
只要访问到,没有限制;但memcache的数据没有持久化保存
尽量选择 sidebar 位于页面右侧的模板,“搜索引擎蜘蛛”的运动轨迹是从上到下,从左到右,所以网站内容最好在左侧。
确保网页 head 标签中有 keywords 和 description
<head> <meta name="keywords" content="关键词1, 关键词2, 关键词3, ..."> <meta name="description" content="网页描述"> </head>
关键词(Keywords):
提示搜索引擎:本网站内容围绕这些词汇展开。因此 keywords 书写的关键是每个词都能在内容中找到相应的匹配才有利于排名。另外最好不要堆砌关键词,物极必反,Google 不喜欢这样…
描述(Description):
描述部分用简短的句子告诉搜索引擎和访问者关于本网页的主要内容。用该网站的核心关键词搜索后得到的搜索结果中,描述往往显示为标题后的几行描述文字。Description 一般被认为重要性在 title 和 keywords 之后。描述的书写要注意以下问题:
网页优化可以说是从 Title 开始的。在搜索结果中,每个抓取内容的第一行显示的文字就是该页的Title,同样在浏览器中打开一个页面,地址栏上方显示的也是该页的Title。因此,Title可谓一个页面的核心。对Title的书写要注意以下问题:
1、title 简短精炼,高度概括,含有关键词,而不是只有一个博客名。但关键词不宜过多,不要超过3个词组。博客的 title 通常以博客名 + 关键词为内容
2、前几个词对搜索引擎最重要,因此关键词位置尽量靠前。
3、最好将 title 组织成符合语法结构和阅读习惯的短句或短语,避免无意义的词组罗列式 title
每一篇文章或者页面都有相应标题,它都会显示在浏览器的标题栏上。最好的显示方式如下:
文章或页面标题位于最前面,后面才是站点的标题——让“蜘蛛”第一时间知道这张网页是干嘛的。
<title> <?php wp_title(''); if (is_search()) { ?> 搜索 <?php echo $s; } if ( !(is_404()) and (is_search()) or (is_single()) or (is_page()) or (function_exists('is_tag') and is_tag()) or (is_archive()) ) { ?> » <?php } ?> <?php bloginfo('name'); ?> </title>
Wordpress 中具体 title 标签的写法请参照上面。
另外优化 Title 和 Meta 标签,Wordpress 有一个 SEO ALL IN ONE 的插件很不错,值得一试!
图片地图来取代多个导航图片 合并脚本和样式表
Cache-Control: max-age= Expires:缓存的不仅仅是图片,还有脚本,样式表和flash组件,但不应该包括html
Content-Encoding: gzip Vary: Accept-Encoding 指定代理缓存多个版本请求
使用LINK标签将CSS放在文档HEAD中
禁用expression语法
将javascript和CSS放到外部文件中虽然单从速度而言,内嵌比引用少了http请求,速度加快,但考虑进“缓存及重用”因素,则引用更有利。
设置 Keep-Alive 长连接 页面中引用不要超过2个域名 修改浏览器参数DnsCacheTimeout -> 30 m KeepAliveTimeout -> 1 m ServerInfoTimeout -> 2 m
使用JSMin ShrinkSafe除了与jsmin一样精简代码,还会缩短变量名,这会造成一定的混淆的风险,当两者在压缩时,几乎没什么差别,因此,建议JSMin精简代码更为可靠
重复脚本损伤性能:不必要的HTTP请求和执行js所浪费的时间利用php来避免重复脚本
<?php function insertScripts($jsfile){ if(alreadyInserted($jsfile)){ return; } pushInserted($jsfile); if(hasDependencies($jsfile)){ $dependencies = getDependencies($jsfile); foreach($dependencies as $scripts){ insertScripts($scripts); } } echo '<script type="text/javascript" src="'.$jsfile.'"></script>'; } ?>
PHP代码:
<? $lan = substr($HTTP_ACCEPT_LANGUAGE,0,5); if ($lan == "zh-cn") print("<meta http-equiv='refresh' content = '0;URL = gb/index.htm'>"); else print("<meta http-equiv='refresh' content = '0;URL = en/index.htm'>"); ?>
HTML网页根据来访这的浏览器语言不同自动跳转多语言页面 在 <head> </head> 之间加入如下代码:
<script> var type=navigator.appName if (type=="Netscape") var lang = navigator.language else var lang = navigator.userLanguage //cut down to first 2 chars of country code var lang = lang.substr(0,2) // 英语 if (lang == "en") window.location.replace('url') // 简体中文 else if (lang == "zh-cn") window.location.replace('url') // 繁体中文 else if (lang == "zh-tw") window.location.replace('url') // 德语 else if (lang == "de") window.location.replace('url') // 除上面所列的语言 else window.location.replace('url') </script>
OrangeHRM是一套开源的人力资源管理系统,帮助企业管理公司的人力资源。OrangeHRM是开源的就是说你可以免费的的使用。OrangeHRM基于PHP MySQL平台搭建,有多个模块构成方便日后的功能扩展和升级。OrangeHRM是SourceForge非常热门的一个开源项目,备受国内外关注。
配置环境使用了Nginx+PHP-FPM,因为OrangeHRM使用了symfony这个框架,所以,对php-fastcgi模式要做些调整
server { listen 80; server_name hrm.152153.com; root /usr/yupoo/app/orangehrm-2.6.12.1; index index.html index.htm index.php; expires off; access_log /usr/yupoo/logs/orangehrm-2.6.12.1/access.log main; error_log /usr/yupoo/logs/orangehrm-2.6.12.1/error.log; location ~ ^(.+\.php)(.*)$ { fastcgi_pass 9900.php.com; include common/fastcgi_params; fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_param PATH_INFO $fastcgi_path_info; fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info; fastcgi_param HTTPS off; } }
目前PHP的模板可以说是很多了,有功能强大的smarty,还有简单易用的smarttemplate等。它们每一种模板,都有一个获取输出内容的函数。我们生成静态页面的方法,就是利用了这个函数。用这个方法的优点是,代码比较清晰,可读性好。
这里我用smarty做例子,说明如何生成静态页
<?php require('smarty/Smarty.class.php'); $t = new Smarty; $t->assign("title","Hello World!"); $content = $t->fetch("templates/index.htm"); //这里的 fetch() 就是获取输出内容的函数,现在$content变量里面,就是要显示的内容了 $fp = fopen("archives/2005/05/19/0001.Html", "w"); fwrite($fp, $content); fclose($fp); ?>
这里用到的函数主要是 obstart(), obendflush(), obgetcontent(),其中obstart()是打开浏览器缓冲区的意思,打开缓冲后,所有来自PHP程序的非文件头信息均不会发送,而是保存在内部缓冲区,直到你使用了obendflush().而这里最重要的一个函数,就是obgetcontents(),这个函数的作用是获取缓冲区的内容,相当于上面的那个fetch(),道理一样的。
<?php ob_start(); echo "Hello World!"; $content = ob_get_contents();//取得php页面输出的全部内容 $fp = fopen("archives/2005/05/19/0001.html", "w"); fwrite($fp, $content); fclose($fp); ?>
<? $ver = "1.0.0"; $copy="<!-- nsTWP v$ver :: nst.void.ru --> <!-- Network security team --> <!-- Public version -->"; if(!$_GET['address']){ die(" <title>nsT web proxy $ver</title> <body bgcolor=black> <center> <form method=get><span id=\"more-89\"></span> <font face=verdana size=1 color=silver> PHP Web proxy :: <a href=http://nst.e-nex.com style='text-decoration:none'>nst.e-nex.com</a>\\ Address: <input name=address size=50 style='border: 1px; background-color: #1A1A1A; color: green;' autocomplete=off> \\ Expl: <b>nst.e-nex.com</b> or <b>some_web.net/cmd.php?cmd=ls -la</b> \\ nsTWP v$ver </form></font></center>\n $copy "); }else{ $address = $_GET['address']; $php_self= $_SERVER['PHP_SELF']; # v1.1 # $x=$address; $c=strlen($x); if($x{0}.$x{1}.$x{2}.$x{3}.$x{4}.$x{5}.$x{6}=="http://"){ for($i=7; $i<$c; $i++){ $total.=$x{$i}; } $address=$total; } # end of v1.1 # $get_add = explode("/",$address,2); if($_GET['address']){ $fp = @fsockopen($get_add[0], 80); $out = "GET /$get_add[1] HTTP/1.0\r\n"; $out .= "Host: $get_add[0]\r\n"; $out .= "\r\n"; $out .= "Connection: Close\r\n\r\n"; for(fwrite($fp, $out);trim(fgets($fp));); while (!feof($fp)) { $info.=fgets($fp, 128); } fclose($fp); $script_url=$php_self; $web=$info; preg_match_all("#\s(href|src|action|codebase|url)=([\"\'])?(.*?)([\"\'])?([\s\>])#i", $web, $matches, PREG_SET_ORDER); foreach ($matches as $match) { $uri = trim($match[3]); $fragment = ($hash_pos = strpos($uri, '#') !== false) ? '#' . substr($uri, $hash_pos) : ''; $addr=parse_url("http://".$address."/"); $path=pathinfo($addr['path']); $path=$path['dirname']; $path=str_replace("\\","",$path); if(!eregi("$address",$uri) and !eregi("http://",$uri)){$uri="http://".$addr['host']."/$path/$uri";} if(substr_count($uri, "http://".$addr['host']."/")>1){$uri=str_replace("http://".$addr['host']."/","",$uri); $uri="http://".$addr['host']."/$uri";} $url=$uri; $c=strlen($url); for($i=0; $i<$c; $i++){ $cp=substr($url, $i, $i+1); if(substr($url,$i-2,2)=="//" and substr($url,$i-3,3)!="://"){ $url=substr_replace($url, '', $i-2, 1); } } $uri=$url; $replace = ' ' . $match[1] . '=' . $match[2] . $script_url . '?address=' . $uri . $fragment . $match[4] . $match[5]; $web = str_replace($match[0], $replace, $web); } print $web; } #end of go } ?>
/** * 读取文件前几个字节 判断文件类型 * * @return String */ function checkTitle($filename) { $file = fopen($filename, "rb"); $bin = fread($file, 2); //只读2字节 fclose($file); $strInfo = @unpack("c2chars", $bin); $typeCode = intval($strInfo['chars1'].$strInfo['chars2']); $fileType = ''; switch ($typeCode) { case 7790: $fileType = 'exe'; break; case 7784: $fileType = 'midi'; break; case 8297: $fileType = 'rar'; break; case 255216: $fileType = 'jpg'; break; case 7173: $fileType = 'gif'; break; case 6677: $fileType = 'bmp'; break; case 13780: $fileType = 'png'; break; default: $fileType = 'unknown'.$typeCode; } //Fix if ($strInfo['chars1']=='-1' && $strInfo['chars2']=='-40' ) { return 'jpg'; } if ($strInfo['chars1']=='-119' && $strInfo['chars2']=='80' ) { return 'png'; } return $fileType; }
对于上传文件类型的判断,一直没有太好的办法,即使使用上面的代码,也有办法构造假的图片的,有人使用getimagesize来判断,不失为一种好办法:
if(in_array($attach['ext'], array('jpg', 'jpeg', 'gif', 'png', 'swf', 'bmp')) && function_exists('getimagesize') && !@getimagesize($target)) { @unlink($target); upload_error('post_attachment_ext_notallowed', $attacharray); }
header('Content-Type: application/force-download');
header(“Content-Transfer-Encoding: binary”);
if($type == 'html' || $type =='htm') { header('Content-Disposition: attachment; filename="'.$name.'"'); echo file_get_contents(dirname(__FILE__).'/..'.$path); } else if($type == 'xls') { header("Content-Type: application/vnd.ms-excel; charset=utf8"); header("Content-Disposition: attachment; filename=$name"); echo file_get_contents(dirname(__FILE__).'/..'.$path); } elseif($type == 'zip'){ header('Content-Type: application/force-download'); header("Content-Transfer-Encoding: binary"); header("Content-Disposition: attachment; filename=$name"); echo file_get_contents(dirname(__FILE__).'/..'.$path); } function get_file_type($name) { if(strpos($name,".") === false) { return ""; } else { $arr=explode('.', $name); return array_pop($arr); } }
<meta http-equiv="refresh" content="3; url=http://www.google.com">
<?php header("refresh:3;url=http://www.google.com"); print('正在加载,请稍等...三秒后自动跳转!'); /* @功能:等待指定的时间,然后再跳转到指定页面(代替html meta方式) 补充说明: 若等待时间为0,则与header("location:")等效。 */ ?>
参考资料 BigPipe学习研究
<!doctype> <html> <head> <meta charset="utf-8" /> <title>php实现BigPipe</title> </head> <style> </style> <body> <div class="wrapper"> <hr> <div class="section" id="con1">内容1,正在加载……</div> <hr> <div class="section" id="con2">内容2,正在加载……</div> <hr> <div class="section" id="con3">内容3,正在加载……</div> <hr> </div> <?php /* * 输出缓存区 */ function flush_now(){ ob_flush(); flush(); } flush_now(); ?> <?php sleep(2);?> <script> document.getElementById("con1").innerHTML="====内容1===="; </script> <?php flush_now()?> <?php sleep(2);?> <script> document.getElementById("con2").innerHTML="====内容2===="; </script> <?php flush_now()?> <?php sleep(2);?> <script> document.getElementById("con3").innerHTML="====内容3===="; </script> <?php flush_now()?> </body> </html>
output_buffering=4096
open_basedir可将用户访问文件的活动范围限制在指定的区域,通常是其家目录的路径,也可用符号“.”来代表当前目录。
注意用open_basedir指定的限制实际上是前缀,而不是目录名。
若"open_basedir = /dir/user", 那么目录 "/dir/user" 和 "/dir/user1"都是可以访问的。
"open_basedir = /dir/user/"
openbasedir也可以同时设置多个目录, 在Windows中用分号分隔目录,在任何其它系统中用冒号分隔目录。当其作用于Apache模块时,父目录中的openbasedir路径自动被继承。
ansible -i lists_web_new WEB-HGH-8@8-* -m copy -a "src=vivi_php_5328.tgz dest=/root/" -f5 ansible -i lists_web_new WEB-HGH-8@8-* -a "tar zxvf /root/vivi_php_5328.tgz -C /" -f5
ansible -i lists_web_new WEB-HGH-8@8-* -a "/usr/local/vivi/update_vivi.sh" -f2 ansible -i lists_web_new WEB-HGH-8@8-* -a "/etc/init.d/php-fpm start;/etc/init.d/vivi config;/etc/init.d/vivi start" -f2新增了 API→PHP-FPM 变量NGINX_API_UPSTREAM_PHP=" 192.168.1.220:9901 192.168.1.221:9901 192.168.1.222:9901 192.168.1.223:9901 192.168.1.224:9901 192.168.1.225:9901 192.168.1.226:9901 192.168.1.227:9901 "
LVS_VIP_CTC="183.129.206.168" LVS_VIP_CNC="121.52.229.71" ### Keepalived used parameters LVS_MASTER=Y LVS_HOSTS_CTC="183.129.206.169 183.129.206.170 183.129.206.171 183.129.206.172" LVS_HOSTS_CNC="121.52.229.72 121.52.229.73 121.52.229.74 121.52.229.75" LVS_DEV="eth0"ansible -i lists_web_new UPWEB-PHP-220 -m shell -a "chkconfig keepalived on" -f10 ansible -i lists_web_new UPWEB-PHP-221 -m shell -a "chkconfig keepalived on" -f10 ansible -i lists_web_new WEB-HGH-8@8-WY -m shell -a "sed -r -i -e '/LVS_VIP_CTC=/s:.*:LVS_VIP_CTC=\"183.129.206.168\":g' /etc/upyun.cfg" -f10 ansible -i lists_web_new WEB-HGH-8@8-WY -m shell -a "sed -r -i -e '/LVS_VIP_CNC=/s:.*:LVS_VIP_CNC=\"121.52.229.71\":g' /etc/upyun.cfg" -f10
#!/bin/sh IPT="/usr/local/iptables/sbin/iptables" SSH_PORT=`awk '/^Port/{print $2}' /etc/ssh/sshd_config` [ -z $SSH_PORT ] && SSH_PORT=22 echo 1 > /proc/sys/net/ipv4/ip_forward echo 1 > /proc/sys/net/ipv4/conf/lo/arp_ignore echo 2 > /proc/sys/net/ipv4/conf/lo/arp_announce echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore echo 2 > /proc/sys/net/ipv4/conf/all/arp_announce echo 1 > /proc/sys/net/ipv4/conf/all/send_redirects echo 1 > /proc/sys/net/ipv4/conf/default/send_redirects start(){ $IPT -F $IPT -P INPUT DROP NETWORK=`ifconfig |awk '/inet.*addr.*Mask/{split($2,a,":");print a[2]}'` for addr in $NETWORK;do if [[ $addr =~ "127.0.0.1" ]];then NET=$addr elif [[ $addr =~ "192.168." ]];then NET=$addr/16 else NET=$addr/24 fi $IPT -A INPUT -s $NET -j ACCEPT done $IPT -A INPUT -p icmp -j ACCEPT $IPT -A INPUT -p tcp -m multiport --dports $SSH_PORT,80,443 -j ACCEPT } stop(){ $IPT -F $IPT -P INPUT ACCEPT } case $1 in start) start;; stop) stop;; *) echo "$0 start|stop";; esac
ip ro add 192.168.0.0/16 via 192.168.1.1 dev eth1 ip ro fl ca
<?php $to="lighthuang@audividi.com"; $subject="A calendar email testing"; $message=""; $body="aaaa\\nbbb"; $from="From: postmaster <postmaster@audividi.com>"; $start="DTSTART:20071009T073000Z"; $end="DTEND:20071009T093000Z"; $location="LOCATION: http://192.168.3.6/"; $uid="UID:333333333333333333"; $delay="TRIGGER:-PT10M"; $headers=$from; $headers .=' X-Message-Flag: =?gb2312?B?x+u08rXnu7A=?= MIME-Version: 1.0 Content-Type: text/calendar; method=REQUEST;charset=utf-8 Content-Transfer-Encoding: 8bit BEGIN:VCALENDAR VERSION:2.0 METHOD:REQUEST BEGIN:VEVENT ATTENDEE;ROLE=REQ-PARTICIPANT;RSVP=TRUE:MAILTO:GeminisShao@audividi.com ATTENDEE;ROLE=REQ-PARTICIPANT;RSVP=TRUE:MAILTO:postmaster@audividi.com ORGANIZER:MAILTO:peterwang@audividi.com '; $headers .=$start."\n"; $headers .=$end."\n"; $headers .=$location; $headers .=' TRANSP:OPAQUE SEQUENCE:0 '; $headers .=$uid; $headers .=' DTSTAMP:20070912T090711Z DESCRIPTION:..:\n..:\n\n*~*~*~*~*~*~*~*~*~*\n\n'; $headers .=$body."\n"; $headers .="SUMMARY:".$subject; $headers .=' PRIORITY:5 X-MICROSOFT-CDO-IMPORTANCE:1 CLASS:PUBLIC X-MICROSOFT-CDO-IMPORTANCE:1 CLASS:PUBLIC BEGIN:VALARM '; $headers .=$delay; $headers .=' ACTION:DISPLAY DESCRIPTION:Reminder END:VALARM END:VEVENT END:VCALENDAR '; mail($to,$subject,$message,$headers); ?>