分类 PHP 下的文章

thrift的php TCompactProtocol库bug

bug描述:读取的boolean类型的值始终为false,这纠结了我半天,本来还以为是因为自己不会java,服务器端的java代码写错,于是经过严密的审查,觉得应该是php端出了问题。

# 找到333行,修改为:
$field_type &= 0x0f;
# 找到343行,在上面添加一行:
$field_type = $this->getTType($field_type);
# 搞定

Yii语言包词条提取

据说是哥半年前写的一个用户管理程序,而现在老大要求程序能切换语言;将原来的词条用英文添进去之后,发现写语言包的时候一个一个提取比较麻烦,所以就写了个程序提取。(目前还只能提取Yii::t里面只有两个参数的情况)

<?php

$fileinfo = new FilesystemIterator('group'); // 目录

$words = array();
while($fileinfo->valid()) {
    
    if($fileinfo->getExtension() === 'php') {
        $filename = $fileinfo->getFilename();
        $fileobject = $fileinfo->openFile();

        while($fileobject->valid()) {
            if(preg_match_all('/Yii::t\(([\'"])([^\'"]*?)\\1\s*,\s*([\'"])(.*?)\\3\)/', $fileobject->current(), $matches)) {
                foreach($matches[4] as $match) {
                    $words[$match] = isset($words[$match]) ? $words[$match] . '; ' . $filename . ' # ' . $fileobject->key() : '// ' . $filename . ' # ' . $fileobject->key();
                }
            }
            $fileobject->next();
        }
    }

    $fileinfo->next();
}


function save_to_file($content = '') {
    $fileobject = new SplFileObject('user.trans.php', 'w');
    $fileobject->fwrite($content);
}

ob_start('save_to_file');

echo '<?php
/**
 * @author XiaoZi<245565986@qq.com>
 */
return array(
';

foreach($words as $word => $comment) {
    echo "\t" . $comment . PHP_EOL;
    echo "\t" . '\'' . $word . '\' => \'\',' . PHP_EOL;
}

echo ');
';

ob_end_clean();

php创建透明缩略图的方法

我所知的两种方法:

  • 非混色模式(透明色具有覆盖的效果)
  • 使新创建的画布透明

方法一、非混色模式

$thumb = imagecreatetruecolor(100, 100);
imagealphablending($thumb, false);
imagesavealpha($thumb, true);
// 裁剪
// imagecopy
// 缩放
// imagecopyresampled

方法二、让画布透明

$canvas = imagecreatetruecolor(100, 100);
$blackcolor = imagecolorallocate($canvas, 0, 0, 0);
imagecolortransparent($canvas, $blackcolor);
// 画个长方形测试一下
imagefilledrectangle($im, 4, 4, 50, 25, $red);

php soap带验证

Server端

<?php
class Server {
    private $authenticated = false;

    public function auth($authcode) {
        if($authcode === '123456789') {
            $this->authenticated = true;
            return true;
        } else {
            throw new SoapFault('403', '403 Forbidden');
        }
    }

    public function getData() {
        if(!$this->authenticated) {
            throw new SoapFault('403', '403 Forbidden');
        }
        $data = array(
            'text' => 'ni mei a'
        );
        return json_encode($data);
    }
}

/*//生成wsdl文件
include("SoapDiscovery.class.php");

$disco = new SoapDiscovery('Server','Server');

$handle = fopen('server.wsdl', 'w+');
fwrite($handle, $disco->getWSDL());
fclose($handle);
*/


$objSoapServer = new SoapServer("server.wsdl");
// $objSoapServer->setClass("Server");
$serv = new Server;
$objSoapServer->setObject($serv);
$objSoapServer->handle();

Client端

<?php
try {
    $client = new SoapClient('server.wsdl',array("exceptions" => 1));

    $authvalues = new SoapVar(array('authcode' => '123456789',), SOAP_ENC_OBJECT);

    $header = new SoapHeader('urn:Server', 'auth', $authvalues, false, SOAP_ACTOR_NEXT);

    $client->__setSoapHeaders(array($header));
    $data = $client->getData();

    var_dump($data);
} catch (SoapFault $e) {
    echo $e->faultstring;
}

php pdo操作mysql数据库

连接mysql

$db = new PDO('mysql:host=localhost;dbname=mydb;charset=utf8', 'root', '');

操作数据库

$rs = $db->prepare('SELECT * FROM pre_member m LEFT JOIN pre_group g ON m.groupid=g.gid WHERE m.username=:username');
$rs->execute(array(':username' => $username));
//fetchObject()
while($row = $rs->fetch()) {
    //...
}

注意

//每次操作完之后都要关闭游标,否则下次运行sql语句的时候会出现问题。
$rs->closeCursor();

变量的作用域

php的变量作用范围

$str = 'something';
function infunction() {
    echo $str; //报错
}
function infunc() {
    $str = 'one two three';
    echo $str; //one two three
}
echo $str; //something
//不搭嘎啊

javascript变量作用范围

var str = 'something';
function infunction() {
    console.log(str); //something
    str = 'one two three';
}
console.log(str); //one two three
//想function里面的变量私有化,则需要var来定义

python变量作用范围

str = 'something';
def infunction():
    print(str) #something
def infunc():
    print(str) #报错
    str = 'one two three'
#在def中不对外部变量赋值时,外部变量可直接使用(global)
#一旦在def中对变量复制,def中的变量将会私有化(locale)

实时网站在线人数显示

javascript部分

使用的ajax长轮询 ajax long poll,为了便于使用,我将它封装成了一个jquery插件

(function($){
	$.fn.extend({
		visitors: function(options){
			var defaults = {
				script : "visitors/online.php",
				timeout : 50000,
			};
			var options = $.extend(defaults, options);
			return this.each(function(){
				var holder = $(this);
				refresh = function(sleep) {
					var sleep = sleep ? sleep : 1000;
					setTimeout('update()', sleep);
				}
				update = function() {
					$.ajax({
						url : options.script,
						type : 'get',
						dataType : 'json',
						async : true,
						cache : false,
						timeout : options.timeout,
						beforeSend : function() {
						},
						success : function(data) {
							holder.html(data.num);
							refresh(1000);
						},
						error : function() {
							refresh(15000);
						}
					});
				}
				update();
			});
		}
	});
})(jQuery);

php部分

待续...

php杂记

逻辑运算

对于整个表达式来说:

或(|| or)两个同时为真则为真
与(&& and)有一个为真则为真
#这里可以用三目运算实现,这里只是为了说明逻辑关系。
$data = array(
    array('a'=>'a','b'=>''),
    array('a'=>'','b'=>'b'),
    array('a'=>'a','b'=>'b')
);
while(list(,$item) = each($data)) {
    ($item['a'] and $item['b']) and ($result = $item['a'] . $item['b']) or ($item['a'] and ($result = $item['a'])) or ($item['b'] and ($result = $item['b']));
    var_dump($result);
}
// string(1) "a"
// string(1) "b"
// string(2) "ab"

位运算

位的偏移运算,2进制

//   1
// 100 化成十进制 2的平方 = 4
echo 1<<2;

类型自动转换

可悲啊,在公司的群里面,发了下面的一道,居然没有一个人去尝试执行结果。

var_dump(0 == 'string'); // true
var_dump(true == 'string'); // true
var_dump(0 == false); //true

都是true?相信后两个的执行结果都能理解,为什么第一个也是true呢?
intval('string'); //0 看到木有,当字符串跟数字比较的时候,php会自动转换字符串为数字,啊哈。再来看看这个 intval('2string'); //2

创建多级目录

mkdir('/test1/test2', 0777, true); //最后一个参数设为true就可以了

正则杂记

验证手机号码

中国移动号段 1340-1348 135 136 137 138 139 150 151 152 157 158 159 187 188 147
中国联通号段 130 131 132 155 156 185 186 145
中国电信号段 133 1349 153 180 189
其他 181 182 183 184
^(13[0-9]|15[0-9]|14[0-9]|18[0-9])\d{8}$
^(1[3-5][0-9]|18[0-9])\d{8}$
^(1[3-58])\d{9}$

验证邮箱

^\w[-\w.+]*@([A-Za-z0-9][-A-Za-z0-9]+\.)+[A-Za-z]{2,4}$

验证日期

^((((1[6-9]|[2-9]\d)\d{2})-(0?[13578]|1[02])-(0?[1-9]|[12]\d|3[01]))|(((1[6-9]|[2-9]\d)\d{2})-(0?[13456789]|1[012])-(0?[1-9]|[12]\d|30))|(((1[6-9]|[2-9]\d)\d{2})-0?2-(0?[1-9]|1\d|2[0-8]))|(((1[6-9]|[2-9]\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00))-0?2-29-))$

验证时间

格式:时:分:秒

^([01]?\d|2[0-3]):[0-5]?\d:[0-5]?\d$

验证url

^\b(((https?|ftp):\/\/)?[-a-z0-9]+(\.[-a-z0-9]+)*\.(?:com|edu|gov|int|mil|net|org|biz|info|name|museum|coop|aero|[a-z][a-z]|((25[0-5])|(2[0-4]\d)|(1\d\d)|([1-9]\d)|\d))\b(\/[-a-z0-9_:\@&?=+,.!\/~%\$]*)?)$

环视

以前一直没明白正则的环视的使用环境,网上的那些例子不用环视也能写出来,而且更容易理解。其实,在需要匹配的字符串有长度限制的时候,而且有其他的特殊要求的时候,用环视能很好的解决问题。这样说,还太抽象了,下面看例子:

#有待更新

一些注册表单会用到的正则

用户名(允许字母、数字、下划线、减号、中文)

^[A-Za-z0-9_\-\u4e00-\u9fa5]+$
^[A-Za-z0-9_\-\x{4e00}-\x{9fa5}]+$

真实姓名(允许字母、中文)

^[A-Za-z\u4e00-\u9fa5]+$    // js
^[A-Za-z\x{4e00}-\x{9fa5}]+$    // php

http及https的url

^http[s]?:\/\/([\w-]+\.)+[\w-]+([\w-./?%&=]*)?$

IP v4,下面把四个展开写是为了看起来比较直观,其实可以写的更短一点。

^(25[0-5]|2[0-4]\d|[0-1]\d{2}|[1-9]?\d)\.(25[0-5]|2[0-4]\d|[0-1]\d{2}|[1-9]?\d)\.(25[0-5]|2[0-4]\d|[0-1]\d{2}|[1-9]?\d)\.(25[0-5]|2[0-4]\d|[0-1]\d{2}|[1-9]?\d)$

验证子网掩码

^(((255\.){3}(255|254|252|248|240|224|192|128|0+))|((255\.){2}(255|254|252|248|240|224|192|128|0+)\.0)|((255\.)(255|254|252|248|240|224|192|128|0+)(\.0+){2})|((255|254|252|248|240|224|192|128|0+)(\.0+){3}))$

flush这个函数

这个函数呢,在每个浏览器下的作用结果是不一样的:

  • IE下,接受到256个字节之后才开始显示
  • Chrome下,接受到2048个字节之后才开始显示

$my_string_var = 'test...';
echo '';
for($i = 1, $i <7, $i++) {
	echo str_pad($my_string_var, 2048, ' ');
	@ob_flush();
	flush();
	sleep(1);
}

file_get_contents这个函数

当要获取的URL资源不存在的时候,这个函数在linux和windows下返回的结果是不一样的。

在windows下,当访问的页面返回404的时候,file_get_contents不会去获取response的body的值,会返回false

而在linux下他会去获取404的HTML页面的内容。

上述情况和网络环境有关。

所以去判断一个远程文件是否存在的时候,不能使用file_get_contents($url,0,null,0,1),而应当去获取response的头状态。

php调用python服务

侃侃:公司用的php的popen以命令的形式调用python,首先说说这样做的缺点。

php执行命令行调用python的缺点

popen('python test.py [参数]', 'r');
  1. 缺点一:windows默认的是gbk编码,当php中传utf-8中文参数的时候,python接收到的参数会有问题。

    #当然,这是有解决的办法的,就是windows下转换一下字符的编码,linux不用转换。再来python接收参数的时候肯定也要转换编码了,烦不烦?
  2. cmd命令或者shell命令是有长度限制的,传的参数过长的时候,接收到的参数就不会完整。
  3. 执行shell命令是有危险的,万一参数里面多了个啥,你知道的。

    #这也能解决,php中的函数escapeshellarg,嗯哼先给他escape一下。
    

那怎么办呢?

python socket server

不多说,不清楚的百度"socket",下面上代码(写的一个php调用python服务美化javascript的应用,服务器端python):

#代码中引用的模块将会在附件中给出
import sys, json
import traceback
import SocketServer
from daemon import Daemon
import jsbeautifier

class Todo:
    def __init__(self):
        print('Welcome!')
    def test(self, args):
        res = jsbeautifier.beautify(args[0].encode('utf-8'))
        return res;
    def error(self, args):
        return 'not function!'

class ThreadedTCPRequestHandler(SocketServer.BaseRequestHandler):
    def handle(self):
        while True:
            try:
                data = self.request.recv(1024)
                if not data:
                    print('end')
                    break
                data = json.loads(data)
                res =  getattr(self._object, data['func'], 'error')(data['args'])
                if not res:
                    res = ''
                res = str(len(res)).rjust(8, '0') + str(res)
                self.request.send(res)
            except:
                print('error in ThreadedTCPRequestHandler :%s, res:%s' % (traceback.format_exc(), data))

class ThreadedTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
    pass

class Server(Daemon):        
    def conf(self, host, port, obj):
        self.host = host
        self.port = port
        self.obj = obj
        ThreadedTCPServer.allow_reuse_address = True
    def run(self):
        ThreadedTCPRequestHandler._object = self.obj
        server = ThreadedTCPServer((self.host, self.port), ThreadedTCPRequestHandler)
        server.serve_forever()

if __name__ == '__main__':
    server = Server('/tmp/daemon-tortoise.pid')
    server.conf('0.0.0.0', 1990, Todo())
    if len(sys.argv) == 2:
        if 'start' == sys.argv[1]:
            server.start()
        elif 'stop' == sys.argv[1]:
            server.stop()
        elif 'restart' == sys.argv[1]:
            server.restart()
        else:
            print("Unknown command")
            sys.exit(2)
        sys.exit(0)
    else:
        print("usage: %s start|stop|restart" % sys.argv[0])
        sys.exit(2)

解释一下,上面这些代码是用python创建一个socket服务器,并且加入系统的守护进程。Todo里面实现策略工厂啥的,你懂的。使用方法:

python sever.py [start|stop|restart]
#接着设为系统启动项就O了。

php通过socket调用python

//代码中引用的文件将会在附件中给出,附件中还给出了php并发的写法
require 'socketapi.php';
header("Content-type: text/html; charset=utf-8");
$s = new server('192.168.1.8', 1990);
$code = <<<EOT
/*   美化:格式化代码,使之容易阅读            */
/*   净化:去掉代码中多余的注释、换行、空格等    */
/*   压缩:将代码压缩为更小体积,便于传输        */
/*   解压:将压缩后的代码转换为人可以阅读的格式    */

/*   如果有用,请别忘了推荐给你的朋友:        */
/*   javascript在线美化、净化、压缩、解压:http://box.inote.cc/js   */

/*   以下是演示代码                */

    var getPositionLite = function(el) {        var x = 0,        y = 0;        while (el) {            x += el.offsetLeft || 0;            y += el.offsetTop || 0;            el = el.offsetParent        }        return {            x: x,            y: y        }    };
/*   更新记录:                    */
    var history = {
        'v1.0':    ['2011-01-18','javascript工具上线']
    };
EOT;
$res = $s->obj('Todo')->test($code);
echo '<pre>'.$res.'</pre>';

附件,你懂的。

client.zip | server.zip