yum安装 lnmp (linux+nginx+php7.1+mysql5.7)

1、第一步先更新yum update

2、yum安装nginx
安装nginx最新源:
yum localinstall http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm
yum repolist enabled | grep “nginx*”
安装nginx:
yum -y install nginx
启动nginx:
service nginx start
设置nginx服务器开机自启动:
systemctl enable nginx.service
检查开机自动是否设置成功:
systemctl list-dependencies | grep nginx

3、yum安装mysql5.7
安装mysql源:
yum -y localinstall http://dev.mysql.com/get/mysql57-community-release-el7-7.noarch.rpm
yum repolist enabled | grep “mysql.*-community.*”
安装mysql:
yum -y install mysql-community-server mysql-community-devel
启动mysql:
service mysqld start
检查mysql启动是否正常:
service mysqld status 或者 ps -ef | grep mysql
设置mysqld服务开机自启动:
systemctl enable mysqld.service
检查mysqld开机自启动是否设置成功:
systemctl list-dependencies | grep mysqld

#查看密码和修改密码

#查看mysql的root账号的密码 grep 'temporary password' /var/log/mysqld.log  #登录mysql mysql -uroot -p  #修改密码 ALTER USER 'root'@'localhost' IDENTIFIED BY 'password';  #修改root用户可远程登录 GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'password' WITH GRANT OPTION;  #刷新 flush privileges;

4、yum安装php7.1
安装php源:
rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
rpm -Uvh https://mirror.webtatic.com/yum/el7/webtatic-release.rpm
检查源是否安装成功;
yum repolist enabled | grep “webtatic*”
安装php扩展源:
yum -y install php71w php71w-fpm
yum -y install php71w-mbstring php71w-common php71w-gd php71w-mcrypt
yum -y install php71w-mysql php71w-xml php71w-cli php71w-devel
yum -y install php71w-pecl-memcached php71w-pecl-redis php71w-opcache
验证php7.1.x和扩展是否安装成功 :
验证php是否安装成功
php -v
验证对应的扩展是否安装成功
php -m
设置php-fpm并检测php-fpm的运行状态:
启动php-fpm
service php-fpm star
检查启动是否成功
service php-fpm status
设置开机自启动:
systemctl enable php-fpm.service
检查开机自启动是否设置成功:
systemctl list-dependencies | grep php-fpm
ps -ef | grep php-fpm

################################################
5.单独安装redis
yum install redis
#修改配置
vi /etc/redis.conf
#daemonize yes 后台运行
#appendonly yes 数据持久化
service redis start

6.安装php-redis扩展
#先装git
yum install git

#git下扩展
cd /usr/local/src
git clone https:#github.com/phpredis/phpredis.git

#安装扩展
cd phpredis
phpize

#修改php配置
vi /etc/php.ini 添加extension=redis.so

#重启php
service php-fpm restart

yum安装 lnmp (linux+nginx+php7.1+mysql5.7)

1、第一步先更新yum update

2、yum安装nginx
安装nginx最新源:
yum localinstall http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm
yum repolist enabled | grep “nginx*”
安装nginx:
yum -y install nginx
启动nginx:
service nginx start
设置nginx服务器开机自启动:
systemctl enable nginx.service
检查开机自动是否设置成功:
systemctl list-dependencies | grep nginx

3、yum安装mysql5.7
安装mysql源:
yum -y localinstall http://dev.mysql.com/get/mysql57-community-release-el7-7.noarch.rpm
yum repolist enabled | grep “mysql.*-community.*”
安装mysql:
yum -y install mysql-community-server mysql-community-devel
启动mysql:
service mysqld start
检查mysql启动是否正常:
service mysqld status 或者 ps -ef | grep mysql
设置mysqld服务开机自启动:
systemctl enable mysqld.service
检查mysqld开机自启动是否设置成功:
systemctl list-dependencies | grep mysqld

#查看密码和修改密码

#查看mysql的root账号的密码 grep 'temporary password' /var/log/mysqld.log  #登录mysql mysql -uroot -p  #修改密码 ALTER USER 'root'@'localhost' IDENTIFIED BY 'password';  #修改root用户可远程登录 GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'password' WITH GRANT OPTION;  #刷新 flush privileges;

4、yum安装php7.1
安装php源:
rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
rpm -Uvh https://mirror.webtatic.com/yum/el7/webtatic-release.rpm
检查源是否安装成功;
yum repolist enabled | grep “webtatic*”
安装php扩展源:
yum -y install php71w php71w-fpm
yum -y install php71w-mbstring php71w-common php71w-gd php71w-mcrypt
yum -y install php71w-mysql php71w-xml php71w-cli php71w-devel
yum -y install php71w-pecl-memcached php71w-pecl-redis php71w-opcache
验证php7.1.x和扩展是否安装成功 :
验证php是否安装成功
php -v
验证对应的扩展是否安装成功
php -m
设置php-fpm并检测php-fpm的运行状态:
启动php-fpm
service php-fpm star
检查启动是否成功
service php-fpm status
设置开机自启动:
systemctl enable php-fpm.service
检查开机自启动是否设置成功:
systemctl list-dependencies | grep php-fpm
ps -ef | grep php-fpm

################################################
5.单独安装redis
yum install redis
#修改配置
vi /etc/redis.conf
#daemonize yes 后台运行
#appendonly yes 数据持久化
service redis start

6.安装php-redis扩展
#先装git
yum install git

#git下扩展
cd /usr/local/src
git clone https:#github.com/phpredis/phpredis.git

#安装扩展
cd phpredis
phpize

#修改php配置
vi /etc/php.ini 添加extension=redis.so

#重启php
service php-fpm restart

PHP 之源代码加密与解密,加密后可直接运行

方式一:

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677<?php/*** Created by PhpStorm.* User: Yang* Date: 2019/10/16* Time: 10:25*/  class Encipher { private $_sourceFile '';private $_encodedFile '';private $_comments array('Author: Yang','Email: 1017836267@qq.com'); public function __construct($sourceFile$encodeFile$comments array()){!empty($sourceFile) && $this->_sourceFile = $sourceFile;!empty($encodeFile) && $this->_encodedFile = $encodeFile;!empty($comments) && $this->comments = (array)$comments; if (empty($this->_sourceFile) || !file_exists($this->_sourceFile)) {exit("Source file does not exist.");}if (empty($this->_encodedFile) || !file_exists($this->_encodedFile)) {//如果源文件不存在,则创建fopen($this->_encodedFile, "w");}} /*** 返回随机字符串* @return string*/private function createRandKey()// 返回随机字符串$str "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";return str_shuffle($str);} /*** 加密函数* @return bool*/public function encode() {//随机密匙1$k1 $this->createRandKey();//随机密匙2$k2 $this->createRandKey();// 获取源文件内容$sourceContent file_get_contents($this->_sourceFile);//base64加密$base64 $headers) . "\r\n" $prefixCode), $enkey$dekey);$evalEmbedCode $this->_getEvalEmbedCode($decodeCodeOfHostedCode$regVars$enkey$dekey);/*** eval(base64_decode(*     str_replace("\$hookKey", '', strtr($hookKey.$evalEmbedCode, $dekey, $enkey))* ));* $unset;*/$unset 'unset(' $funcStrVar;foreach ($regVars as $var) {$unset .= ',' $var;}$unset .= ');';$evalCode "@eval(" $regVars["base64_decode"] . "(" $regVars["str_replace"] . "(" $regVars["\$hookKey"] . ",''," $regVars["strtr"] . "('" $hookKey $evalEmbedCode "','" $dekey "','" $enkey "'))));" $unset;$originalEncodedCode $this->_getPHPEncode($file$enkey$dekey);$enCode = implode("\r\n"$headers) . "\r\n" $prefixCode $evalCode "return;?>\r\n" $originalEncodedCode;$this->_saveEncryptFile($file$enCode$enkey$dekey);} /*** The encoded code needs extra code*/private function _getBaseCodeOfHostedCode(){$code = <<<EOT\$farrs   = file(str_replace('\\\\''/'__FILE__));\$enCode  array_pop(\$farrs);\$phpCode array_pop(\$farrs);\$fstrs   = implode('', \$farrs) . substr(\$phpCode, 0, strrpos(\$phpCode'@ev'));\$hookKey = md5(\$fstrs);\$farrs   = \$phpCode = \$fstrs = NULL;EOT;return $code;} /*** The encoded code needs decode code* if the licence is generated, also need to process it.*/private function _getDecodeCodeOfHostedCode($file$enkey$dekey){$code = <<<EOTeval(base64_decode(strtr(\$enCode'{$dekey}''{$enkey}')));\$enCode = NULL;EOT;return $code;} private function _getFuncVarDefCode($usedFuncMaps$funcChars$funcStrVar){//all the chars of function name$funcStr = implode(""$funcChars); //set variable name's value for each variable of function name$funcVarValArr $this->_getFuncVarvalArr($usedFuncMaps$funcChars$funcStrVar); //encoded code define function name string.$code $funcStrVar "='{$funcStr}';";foreach ($usedFuncMaps as $func => $val) {$code .= $val "= " $funcVarValArr[$func] . ";\n";}return $code;} private function _getEvalEmbedCode($decodeCodeOfHostedCode$regVars$enkey$dekey){$code = preg_replace("/\r|\n/is"""strtr($decodeCodeOfHostedCode$regVars));//replace multi space to one, and encode it via base64$code base64_encode(preg_replace("/\s{2,}/is"" "$code));$code strtr($code$enkey$dekey);return $code;} /*** get function names and chars for all functions*/private function _getMatchedFunctions($code){//match all function namepreg_match_all("/([a-z_0-9]+)\(/is"$code$matches);$usedFuncs array_unique($matches[1]);if (false !== ($key array_search('eval'$usedFuncs))) {unset($usedFuncs[$key]);} $funcChars array_unique(preg_split("//is", implode(""$usedFuncs), -1, PREG_SPLIT_NO_EMPTY));shuffle($funcChars);return array(array_flip($usedFuncs), $funcChars);} /*** get variable names*/private function _getMatchedVariables($code){preg_match_all("/(\\\$[a-z0-9]+)\s*\=/is"$code$matches);return array_flip($matches[1]);} private function _getFuncVarvalArr($usedFuncMaps$funcChars$funcStrVar){$funcVarValArr array();foreach ($usedFuncMaps as $func => $_val) {$val "";for ($i = 0, $len strlen($func); $i $len$i++) {if ($val == "") {$val $funcStrVar "{" array_search($func{$i}, $funcChars) . "}";else {$val $val "." $funcStrVar "{" array_search($func{$i}, $funcChars) . "}";}}$funcVarValArr[$func] = $val;}return $funcVarValArr;} /*** get php pure code, trim php tag*/private function _getPHPCode($file){$from $this->source_file . '/' $file;$str file_get_contents($from);$str = preg_replace("/^[\s\xef\xbb\xbf]*<\?php/is"""$str);$str = trim(preg_replace("/\?>\s*$/is"""$str));return $str;} /*** get php encoded code*/private function _getPHPEncode($file$enkey$dekey){$code $this->_getPHPCode($file);$enCode strtr(base64_encode($code), $enkey$dekey);return $enCode;} private function _getKeyPairs(){$enkey $this->_getKeyStr();$dekey $this->_getKeyStr();while ($enkey === $dekey) {$dekey $this->_getKeyStr();}return array($enkey$dekey);} private function _getKeyStr(){$base64str 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';for ($i = 127; $i <= 160; $i++) {$base64str .= chr($i);}$baseChars array_filter(preg_split("//is"$base64str));$baseChars[] = 0;shuffle($baseChars);return implode(""$baseChars);} private function _setVarName($funcs$filter array()){$length $this->varnameLength;$basestr $this->_getInvisibleStr($length);$count count($funcs);if ($count == 0) {return array();}$varArr array();do {$randStr substr("\$" str_shuffle($basestr), 0, rand(2, $length));if (!in_array($randStr$varArr) && !in_array($randStr$filter)) {$varArr[] = $randStr;$count--;}while ($count > 0);return array_combine(array_keys($funcs), $varArr);} /*** legal variable names: '[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*'* Invisiable string's ascii is from 127 to 255:'[\x7f-\xff][\x7f-\xff]*'* param $length  the variable name's length.*/private function _getInvisibleStr($length = 10){$str '';for ($i = 0; $i $length$i++) {$num = rand(127, 255);$str .= chr($num);}return $str;} private function _saveEncryptFile($file$enCode$enkey = null, $dekey = null){$to $this->encoded_file . '/' $file;file_put_contents($to$enCode);echo $to "\n";}}

PHP实现类似百度搜索自动完成(代码简单)

一、效果图:

二、HTML代码

jQuery UI 自动完成(Autocomplete) – 默认功能
标签:

三、PHP代码
prepare(“select title from article where title like :title”);
$result->execute(array(‘title’ => “%” . $keyword . “%”));
$data = $result->fetchall(PDO::FETCH_ASSOC);
//将二维数组转化为一维数组(自动补全插件要求的是一个一维数组)
foreach ($data as $k => $v) {
$datas[] = $v[‘title’];
}
return $datas;
}

//获取输入框的内容
//注:jquery-ui的自动补全ajax 当我们输入一个c时,Autocomplete实际发送的请求路径为at.php?term=c
$keyword = $_GET[‘term’];

//根据用户输入值查询相关数据
$data = test($keyword);
//输出json字符串
echo json_encode($data); //输出查询的结果(json格式输出)

?>
 

备注:HTML部分引入的css,js源代码:

文章参考:http://www.365mini.com/page/jquery-ui-autocomplete.htm

更多功能可参考: http://www.runoob.com/jqueryui/example-autocomplete.html

如果js和css源代码地址找不到,到这里下载

总结:以上是结合mysql 和 jquery-ui实现的自动提示,实际上如果数据库数据量较大的情况,整体对数据库开销也比较大。

这样,也可以尝试使用全文检索工具 xunsearch 或 sphinx 来实现。好处是减少了mysql数据库的查询压力,提高了检索速度。

xunSearch的使用:https://blog.csdn.net/m_nanle_xiaobudiu/article/details/81663636
————————————————
版权声明:本文为CSDN博主「m_nanle_xiaobudiu」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/m_nanle_xiaobudiu/article/details/79343394

PHP 高级编程之多线程-消息队列

1. 多线程环境安装

1.1. PHP 5.5.9

安装PHP 5.5.9

https://github.com/oscm/shell/blob/master/php/5.5.9.sh
./configure --prefix=/srv/php-5.5.9 \--with-config-file-path=/srv/php-5.5.9/etc \--with-config-file-scan-dir=/srv/php-5.5.9/etc/conf.d \--enable-fpm \--with-fpm-user=www \--with-fpm-group=www \--with-pear \--with-curl \--with-gd \--with-jpeg-dir \--with-png-dir \--with-freetype-dir \--with-zlib-dir \--with-iconv \--with-mcrypt \--with-mhash \--with-pdo-mysql \--with-mysql-sock=/var/lib/mysql/mysql.sock \--with-openssl \--with-xsl \--with-recode \--enable-sockets \--enable-soap \--enable-mbstring \--enable-gd-native-ttf \--enable-zip \--enable-xml \--enable-bcmath \--enable-calendar \--enable-shmop \--enable-dba \--enable-wddx \--enable-sysvsem \--enable-sysvshm \--enable-sysvmsg \--enable-opcache \--enable-pcntl \--enable-maintainer-zts \--disable-debug

编译必须启用zts支持否则无法安装 pthreads(–enable-maintainer-zts)

1.2. 安装 pthreads 扩展

安装https://github.com/oscm/shell/blob/master/php/pecl/pthreads.sh

# curl -s https://raw.github.com/oscm/shell/master/php/pecl/pthreads.sh | bash

查看pthreads是否已经安装

# php -m | grep pthreads

2. Thread

<?phpclass HelloWorld extends Thread {    public function __construct($world) {       $this->world = $world;    }     public function run() {        print_r(sprintf("Hello %s\n", $this->world));    }} $thread = new HelloWorld("World"); if ($thread->start()) {    printf("Thread #%lu says: %s\n", $thread->getThreadId(), $thread->join());}?>

3. Worker 与 Stackable

<?phpclass SQLQuery extends Stackable {         public function __construct($sql) {                $this->sql = $sql;        }         public function run() {                $dbh  = $this->worker->getConnection();                $row = $dbh->query($this->sql);                while($member = $row->fetch(PDO::FETCH_ASSOC)){                        print_r($member);                }        } } class ExampleWorker extends Worker {        public static $dbh;        public function __construct($name) {        }         /*        * The run method should just prepare the environment for the work that is coming ...        */        public function run(){                self::$dbh = new PDO('mysql:host=192.168.2.1;dbname=example','www','123456');        }        public function getConnection(){                return self::$dbh;        }} $worker = new ExampleWorker("My Worker Thread"); $work=new SQLQuery('select * from members order by id desc limit 5');$worker->stack($work); $table1 = new SQLQuery('select * from demousers limit 2');$worker->stack($table1); $worker->start();$worker->shutdown();?>

4. 互斥锁

什么情况下会用到互斥锁?在你需要控制多个线程同一时刻只能有一个线程工作的情况下可以使用。

下面我们举一个例子,一个简单的计数器程序,说明有无互斥锁情况下的不同。

<?php$counter = 0;//$handle=fopen("php://memory", "rw");//$handle=fopen("php://temp", "rw");$handle=fopen("/tmp/counter.txt", "w");fwrite($handle, $counter );fclose($handle); class CounterThread extends Thread {public function __construct($mutex = null){ose($this->handle);}    public function run() {if($this->mutex)$locked=Mutex::lock($this->mutex); $counter = intval(fgets($this->handle));$counter++;rewind($this->handle);fputs($this->handle, $counter );printf("Thread #%lu says: %s\n", $this->getThreadId(),$counter); if($this->mutex)Mutex::unlock($this->mutex);    }} //没有互斥锁for ($i=0;$i<50;$i++){$threads[$i] = new CounterThread();$threads[$i]->start(); } //加入互斥锁$mutex = Mutex::create(true);for ($i=0;$i<50;$i++){$threads[$i] = new CounterThread($mutex);$threads[$i]->start(); } Mutex::unlock($mutex);for ($i=0;$i<50;$i++){$threads[$i]->join();}Mutex::destroy($mutex); ?>

我们使用文件/tmp/counter.txt保存计数器值,每次打开该文件将数值加一,然后写回文件。当多个线程同时操作一个文件的时候,就会线程运行先后取到的数值不同,写回的数值也不同,最终计数器的数值会混乱。

没有加入锁的结果是计数始终被覆盖,最终结果是2

而加入互斥锁后,只有其中的一个进程完成加一工作并释放锁,其他线程才能得到解锁信号,最终顺利完成计数器累加操作

上面例子也可以通过对文件加锁实现,这里主要讲的是多线程锁,后面会涉及文件锁。

4.1. 多线程与共享内存

在共享内存的例子中,没有使用任何锁,仍然可能正常工作,可能工作内存操作本身具备锁的功能。

<?php$tmp = tempnam(__FILE__, 'PHP');$key = ftok($tmp, 'a'); $shmid = shm_attach($key);$counter = 0;shm_put_var( $shmid, 1, $counter ); class CounterThread extends Thread {public function __construct($shmid){        $this->shmid = $shmid;    }    public function run() { $counter = shm_get_var( $this->shmid, 1 );$counter++;shm_put_var( $this->shmid, 1, $counter ); printf("Thread #%lu says: %s\n", $this->getThreadId(),$counter);    }} for ($i=0;$i<100;$i++){$threads[] = new CounterThread($shmid);}for ($i=0;$i<100;$i++){$threads[$i]->start(); } for ($i=0;$i<100;$i++){$threads[$i]->join();}shm_remove( $shmid );shm_detach( $shmid );?>

5. 线程同步

有些场景我们不希望 thread->start() 就开始运行程序,而是希望线程等待我们的命令。

$thread->wait();测作用是 thread->start()后线程并不会立即运行,只有收到 $thread->notify(); 发出的信号后才运行

<?php$tmp = tempnam(__FILE__, 'PHP');$key = ftok($tmp, 'a'); $shmid = shm_attach($key);$counter = 0;shm_put_var( $shmid, 1, $counter ); class CounterThread extends Thread {public function __construct($shmid){        $this->shmid = $shmid;    }    public function run() {         $this->synchronized(function($thread){            $thread->wait();        }, $this); $counter = shm_get_var( $this->shmid, 1 );$counter++;shm_put_var( $this->shmid, 1, $counter ); printf("Thread #%lu says: %s\n", $this->getThreadId(),$counter);    }} for ($i=0;$i<100;$i++){$threads[] = new CounterThread($shmid);}for ($i=0;$i<100;$i++){$threads[$i]->start(); } for ($i=0;$i<100;$i++){$threads[$i]->synchronized(function($thread){$thread->notify();}, $threads[$i]);} for ($i=0;$i<100;$i++){$threads[$i]->join();}shm_remove( $shmid );shm_detach( $shmid );?>

6. 线程池

6.1. 线程池

自行实现一个Pool类

<?phpclass Update extends Thread {     public $running = false;    public $row = array();    public function __construct($row) { $this->row = $row;        $this->sql = null;    }     public function run() { if(strlen($this->row['bankno']) > 100 ){$bankno = safenet_decrypt($this->row['bankno']);}else{$error = sprintf("%s, %s\r\n",$this->row['id'], $this->row['bankno']);file_put_contents("bankno_error.log", $error, FILE_APPEND);} if( strlen($bankno) > 7 ){$sql = sprintf("update members set bankno = '%s' where id = '%s';", $bankno, $this->row['id']); $this->sql = $sql;} printf("%s\n",$this->sql);    } } class Pool {public $pool = array();public function __construct($count) {$this->count = $count;}public function push($row){if(count($this->pool) < $this->count){$this->pool[] = new Update($row);return true;}else{return false;}}public function start(){foreach ( $this->pool as $id => $worker){$this->pool[$id]->start();}}public function join(){foreach ( $this->pool as $id => $worker){               $this->pool[$id]->join();}}public function clean(){foreach ( $this->pool as $id => $worker){if(! $worker->isRunning()){            unset($this->pool[$id]);            }}}} try {$dbh    = new PDO("mysql:host=" . str_replace(':', ';port=', $dbhost) . ";dbname=$dbname", $dbuser, $dbpw, array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\'',PDO::MYSQL_ATTR_COMPRESS => true)); $sql  = "select id,bankno from members order by id desc";$row = $dbh->query($sql);$pool = new Pool(5);while($member = $row->fetch(PDO::FETCH_ASSOC)){ while(true){if($pool->push($member)){ //压入任务到池中break;}else{ //如果池已经满,就开始启动线程$pool->start();$pool->join();$pool->clean();}}}$pool->start();    $pool->join(); $dbh = null; } catch (Exception $e) {    echo '[' , date('H:i:s') , ']', '系统错误', $e->getMessage(), "\n";}?>

6.2. 动态队列线程池

上面的例子是当线程池满后执行start统一启动,下面的例子是只要线程池中有空闲便立即创建新线程。

<?phpclass Update extends Thread {     public $running = false;    public $row = array();    public function __construct($row) { $this->row = $row;        $this->sql = null;//print_r($this->row);    }     public function run() { if(strlen($this->row['bankno']) > 100 ){$bankno = safenet_decrypt($this->row['bankno']);}else{$error = sprintf("%s, %s\r\n",$this->row['id'], $this->row['bankno']);file_put_contents("bankno_error.log", $error, FILE_APPEND);} if( strlen($bankno) > 7 ){$sql = sprintf("update members set bankno = '%s' where id = '%s';", $bankno, $this->row['id']); $this->sql = $sql;} printf("%s\n",$this->sql);    } }   try {$dbh    = new PDO("mysql:host=" . str_replace(':', ';port=', $dbhost) . ";dbname=$dbname", $dbuser, $dbpw, array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\'',PDO::MYSQL_ATTR_COMPRESS => true)); $sql     = "select id,bankno from members order by id desc limit 50"; $row = $dbh->query($sql);$pool = array();while($member = $row->fetch(PDO::FETCH_ASSOC)){$id = $member['id'];while (true){if(count($pool) < 5){$pool[$id] = new Update($member);$pool[$id]->start();break;}else{foreach ( $pool as $name => $worker){if(! $worker->isRunning()){unset($pool[$name]);}}}} } $dbh = null; } catch (Exception $e) {    echo '【' , date('H:i:s') , '】', '【系统错误】', $e->getMessage(), "\n";}?>

6.3. pthreads Pool类

pthreads 提供的 Pool class 例子

<?php class WebWorker extends Worker { public function __construct(SafeLog $logger) {$this->logger = $logger;} protected $loger;} class WebWork extends Stackable { public function isComplete() {return $this->complete;} public function run() {$this->worker->logger->log("%s executing in Thread #%lu",  __CLASS__, $this->worker->getThreadId());$this->complete = true;} protected $complete;} class SafeLog extends Stackable { protected function log($message, $args = []) {$args = func_get_args(); if (($message = array_shift($args))) {echo vsprintf("{$message}\n", $args);}}}  $pool = new Pool(8, \WebWorker::class, [new SafeLog()]); $pool->submit($w=new WebWork());$pool->submit(new WebWork());$pool->submit(new WebWork());$pool->submit(new WebWork());$pool->submit(new WebWork());$pool->submit(new WebWork());$pool->submit(new WebWork());$pool->submit(new WebWork());$pool->submit(new WebWork());$pool->submit(new WebWork());$pool->submit(new WebWork());$pool->submit(new WebWork());$pool->submit(new WebWork());$pool->submit(new WebWork());$pool->shutdown(); $pool->collect(function($work){return $work->isComplete();}); var_dump($pool);

7. 多线程文件安全读写(文件锁)

文件所种类。

LOCK_SH 取得共享锁定(读取的程序)。LOCK_EX 取得独占锁定(写入的程序。LOCK_UN 释放锁定(无论共享或独占)。LOCK_NB 如果不希望 flock() 在锁定时堵塞

共享锁例子

<?php $fp = fopen("/tmp/lock.txt", "r+"); if (flock($fp, LOCK_EX)) {  // 进行排它型锁定    ftruncate($fp, 0);      // truncate file    fwrite($fp, "Write something here\n");    fflush($fp);            // flush output before releasing the lock    flock($fp, LOCK_UN);    // 释放锁定} else {    echo "Couldn't get the lock!";} fclose($fp); ?>

共享锁例子2

<?php$fp = fopen('/tmp/lock.txt', 'r+'); /* Activate the LOCK_NB option on an LOCK_EX operation */if(!flock($fp, LOCK_EX | LOCK_NB)) {    echo 'Unable to obtain lock';    exit(-1);} /* ... */ fclose($fp);?>

8. 多线程与数据连接

pthreads 与 pdo 同时使用是,需要注意一点,需要静态声明public static $dbh;并且通过单例模式访问数据库连接。

8.1. Worker 与 PDO

<?phpclass Work extends Stackable {         public function __construct() {        }         public function run() {                $dbh  = $this->worker->getConnection();                $sql     = "select id,name from members order by id desc limit 50";                $row = $dbh->query($sql);                while($member = $row->fetch(PDO::FETCH_ASSOC)){                        print_r($member);                }        } } class ExampleWorker extends Worker {        public static $dbh;        public function __construct($name) {        }         /*        * The run method should just prepare the environment for the work that is coming ...        */        public function run(){                self::$dbh = new PDO('mysql:host=192.168.2.1;dbname=example','www','123456');        }        public function getConnection(){                return self::$dbh;        }} $worker = new ExampleWorker("My Worker Thread"); $work=new Work();$worker->stack($work); $worker->start();$worker->shutdown();?>

8.2. Pool 与 PDO

在线程池中链接数据库

# cat pool.php<?phpclass ExampleWorker extends Worker { public function __construct(Logging $logger) {$this->logger = $logger;} protected $logger;} /* the collectable class implements machinery for Pool::collect */class Work extends Stackable {public function __construct($number) {$this->number = $number;}public function run() {                $dbhost = 'db.example.com';               // 数据库服务器                $dbuser = 'example.com';                 // 数据库用户名                $dbpw = 'password';                               // 数据库密码                $dbname = 'example_real';$dbh  = new PDO("mysql:host=$dbhost;port=3306;dbname=$dbname", $dbuser, $dbpw, array(                        PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\'',                        PDO::MYSQL_ATTR_COMPRESS => true,PDO::ATTR_PERSISTENT => true                        )                );$sql = "select OPEN_TIME, `COMMENT` from MT4_TRADES where LOGIN='".$this->number['name']."' and CMD='6' and `COMMENT` = '".$this->number['order'].":DEPOSIT'";#echo $sql;$row = $dbh->query($sql);$mt4_trades  = $row->fetch(PDO::FETCH_ASSOC);if($mt4_trades){ $row = null; $sql = "UPDATE db_example.accounts SET paystatus='成功', deposit_time='".$mt4_trades['OPEN_TIME']."' where `order` = '".$this->number['order']."';";$dbh->query($sql);.example.com';                      // 数据库服务器$dbuser = 'example.com';                 // 数据库用户名$dbpw = 'password';                               // 数据库密码$dbname = 'db_example';$dbh    = new PDO("mysql:host=$dbhost;port=3306;dbname=$dbname", $dbuser, $dbpw, array(                        PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\'',                        PDO::MYSQL_ATTR_COMPRESS => true                        )                );$sql = "select `order`,name from accounts where deposit_time is null order by id desc"; $row = $dbh->query($sql);while($account = $row->fetch(PDO::FETCH_ASSOC)){        $pool->submit(new Work($account));} $pool->shutdown(); ?>

进一步改进上面程序,我们使用单例模式 $this->worker->getInstance(); 全局仅仅做一次数据库连接,线程使用共享的数据库连接

<?phpclass ExampleWorker extends Worker { #public function __construct(Logging $logger) {#$this->logger = $logger;#} #protected $logger;protected  static $dbh;public function __construct() { }public function run(){$dbhost = 'db.example.com';// 数据库服务器    $dbuser = 'example.com';        // 数据库用户名        $dbpw = 'password';             // 数据库密码$dbname = 'example';// 数据库名 self::$dbh  = new PDO("mysql:host=$dbhost;port=3306;dbname=$dbname", $dbuser, $dbpw, array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\'',PDO::MYSQL_ATTR_COMPRESS => true,PDO::ATTR_PERSISTENT => true)); }protected function getInstance(){        return self::$dbh;    } } /* the collectable class implements machinery for Pool::collect */class Work extends Stackable {public function __construct($data) {$this->data = $data;#print_r($data);} public function run() {#$this->worker->logger->log("%s executing in Thread #%lu", __CLASS__, $this->worker->getThreadId() ); try {$dbh  = $this->worker->getInstance();#print_r($dbh);               $id = $this->data['id'];$mobile = safenet_decrypt($this->data['mobile']);#printf("%d, %s \n", $id, $mobile);if(strlen($mobile) > 11){$mobile = substr($mobile, -11);}if($mobile == 'null'){#$sql = "UPDATE members_digest SET mobile = '".$mobile."' where id = '".$id."'";#printf("%s\n",$sql);#$dbh->query($sql);$mobile = '';$sql = "UPDATE members_digest SET mobile = :mobile where id = :id";}else{$sql = "UPDATE members_digest SET mobile = md5(:mobile) where id = :id";}$sth = $dbh->prepare($sql);$sth->bindValue(':mobile', $mobile);$sth->bindValue(':id', $id);$sth->execute();#echo $sth->debugDumpParams();}catch(PDOException $e) {$error = sprintf("%s,%s\n", $mobile, $id );file_put_contents("mobile_error.log", $error, FILE_APPEND);} #$dbh = null;printf("runtime: %s, %s, %s, %s\n", date('Y-m-d H:i:s'), $this->worker->getThreadId() ,$mobile, $id);#printf("runtime: %s, %s\n", date('Y-m-d H:i:s'), $this->number);}} $pool = new Pool(100, \ExampleWorker::class, []); #foreach (range(0, 100) as $number) {#$pool->submit(new Work($number));#} $dbhost = 'db.example.com';                     // 数据库服务器$dbuser = 'example.com';                 // 数据库用户名$dbpw = 'password';                             // 数据库密码$dbname = 'example';$dbh    = new PDO("mysql:host=$dbhost;port=3307;dbname=$dbname", $dbuser, $dbpw, array(                        PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\'',                        PDO::MYSQL_ATTR_COMPRESS => true                        )                );#print_r($dbh); #$sql = "select id, mobile from members where id < :id";#$sth = $dbh->prepare($sql);#$sth->bindValue(':id',300);#$sth->execute();#$result = $sth->fetchAll();#print_r($result);##$sql = "UPDATE members_digest SET mobile = :mobile where id = :id";#$sth = $dbh->prepare($sql);#$sth->bindValue(':mobile', 'aa');#$sth->bindValue(':id','272');#echo $sth->execute();#echo $sth->queryString;#echo $sth->debugDumpParams();  $sql = "select id, mobile from members order by id asc"; // limit 1000";$row = $dbh->query($sql);while($members = $row->fetch(PDO::FETCH_ASSOC)){        #$order =  $account['order'];        #printf("%s\n",$order);        //print_r($members);        $pool->submit(new Work($members));#unset($account['order']);} $pool->shutdown(); ?>

8.3. 多线程中操作数据库总结

总的来说 pthreads 仍然处在发展中,仍有一些不足的地方,我们也可以看到pthreads的git在不断改进这个项目

数据库持久链接很重要,否则每个线程都会开启一次数据库连接,然后关闭,会导致很多链接超时。

<?php$dbh = new PDO('mysql:host=localhost;dbname=test', $user, $pass, array(    PDO::ATTR_PERSISTENT => true));?>

9. Thread And ZeroMQ

应用场景,我使用触发器监控数据库某个表,一旦发现有改变就通知程序处理数据

9.1. 数据库端

首先安装ZeroMQ 与 MySQL UDF https://github.com/netkiller/mysql-zmq-plugin, 然后创建触发器。

CREATE DEFINER=`dba`@`192.168.%` PROCEDURE `Table_Example`(IN `TICKET` INT, IN `LOGIN` INT, IN `CMD` INT, IN `VOLUME` INT)LANGUAGE SQLNOT DETERMINISTIC READS SQL DATASQL SECURITY DEFINER COMMENT '交易监控'BEGIN DECLARE Example CHAR(1) DEFAULT 'N'; IF CMD IN ('0','1') THEN IF VOLUME >=10 AND VOLUME <=90 THEN select coding into Example from example.members where username = LOGIN and coding = 'Y';IF Example = 'Y' THEN select zmq_client('tcp://192.168.2.15:5555', CONCAT(TICKET, ',', LOGIN, ',', VOLUME));END IF;END IF;END IF;END CREATE DEFINER=`dba`@`192.168.6.20` TRIGGER `Table_AFTER_INSERT` AFTER INSERT ON `MT4_TRADES` FOR EACH ROW BEGIN call Table_Example(NEW.TICKET,NEW.LOGIN,NEW.CMD,NEW.VOLUME);END

9.2. 数据处理端

<?phpclass ExampleWorker extends Worker { #public function __construct(Logging $logger) {#$this->logger = $logger;#} #protected $logger;protected  static $dbh;public function __construct() { }public function run(){$dbhost = '192.168.2.1';// 数据库服务器$dbport = 3306;    $dbuser = 'www';        // 数据库用户名        $dbpass = 'password';             // 数据库密码$dbname = 'example';// 数据库名 self::$dbh  = new PDO("mysql:host=$dbhost;port=$dbport;dbname=$dbname", $dbuser, $dbpass, array(/* PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\'', */PDO::MYSQL_ATTR_COMPRESS => true,PDO::ATTR_PERSISTENT => true)); }protected function getInstance(){        return self::$dbh;    } } /* the collectable class implements machinery for Pool::collect */class Fee extends Stackable {public function __construct($msg) {$trades = explode(",", $msg);$this->data = $trades;print_r($trades);} public function run() {#$this->worker->logger->log("%s executing in Thread #%lu", __CLASS__, $this->worker->getThreadId() ); try {$dbh  = $this->worker->getInstance(); $insert = "INSERT INTO coding_fee(ticket, login, volume, `status`) VALUES(:ticket, :login, :volume,'N')";$sth = $dbh->prepare($insert);$sth->bindValue(':ticket', $this->data[0]);$sth->bindValue(':login', $this->data[1]);$sth->bindValue(':volume', $this->data[2]);$sth->execute();//$sth = null;//$dbh = null; /* 业务实现在此处 */ $update = "UPDATE coding_fee SET `status` = 'Y' WHERE ticket = :ticket and `status` = 'N'";$sth = $dbh->prepare($update);$sth->bindValue(':ticket', $this->data[0]);$sth->execute();//echo $sth->queryString;}catch(PDOException $e) {$error = sprintf("%s,%s\n", $mobile, $id );file_put_contents("mobile_error.log", $error, FILE_APPEND);} #$dbh = null;//printf("runtime: %s, %s, %s, %s\n", date('Y-m-d H:i:s'), $this->worker->getThreadId() ,$mobile, $id);#printf("runtime: %s, %s\n", date('Y-m-d H:i:s'), $this->number);}} class Example {/* config */const LISTEN = "tcp://192.168.2.15:5555";const MAXCONN = 100;const pidfile = __CLASS__;const uid= 80;const gid= 80; protected $pool = NULL;protected $zmq = NULL;public function __construct() {$this->pidfile = '/var/run/'.self::pidfile.'.pid';}private function daemon(){if (file_exists($this->pidfile)) {echo "The file $this->pidfile exists.\n";exit();} $pid = pcntl_fork();if ($pid == -1) { die('could not fork');} else if ($pid) { // we are the parent //pcntl_wait($status); //Protect against Zombie childrenexit($pid);} else {// we are the childfile_put_contents($this->pidfile, getmypid());posix_setuid(self::uid);posix_setgid(self::gid);return(getmypid());}}private function start(){$pid = $this->daemon();$this->pool = new Pool(self::MAXCONN, \ExampleWorker::class, []);$this->zmq = new ZMQSocket(new ZMQContext(), ZMQ::SOCKET_REP);$this->zmq->bind(self::LISTEN); /* Loop receiving and echoing back */while ($message = $this->zmq->recv()) {if($message){$this->pool->submit(new Fee($message));$this->zmq->send('TRUE');}else{$this->zmq->send('FALSE');}}$pool->shutdown();}private function stop(){ if (file_exists($this->pidfile)) {$pid = file_get_contents($this->pidfile);posix_kill($pid, 9);unlink($this->pidfile);}}private function help($proc){printf("%s start | stop | help \n", $proc);}public function main($argv){if(count($argv) < 2){printf("please input help parameter\n");exit();}if($argv[1] === 'stop'){$this->stop();}else if($argv[1] === 'start'){$this->start();}else{$this->help($argv[0]);}}} $example = new Example();$example->main($argv);

使用方法

# php example.php start# php example.php stop# php example.php help

此程序涉及守候进程实现$this->daemon()运行后转到后台运行,进程ID保存,进程的互斥(不允许同时启动两个进程),线程池连接数以及线程任务等等

转载自http://my.oschina.net/neochen/blog/294354

用Python做一只真·多足机器人,钢铁蜈蚣能弯曲还能蠕动

大数据文摘出品

来源:declanoller

编译:徐玲、李世林、陈若朦

足式机器人是如今机器人设计的热点,相较于轮式和履带式机器人,足式设计的优势在于其极强的地形通过能力。

你一定见过模仿人类的两足机器人、犬型和马型的四足机器人、近来爆红的蜘蛛型六足机器人,那你有想过再多来几条腿吗?

控制行走一直是足式机器人的一大设计难点,腿越多则移动越困难。然而,一位名叫Adimin的外国小哥用python做了一只可爬行可弯曲的蜈蚣型机器人。

问:为什么要做设计成蜈蚣型呢?

小哥答:蜈蚣在体型上具有相当的长度,而通过向上弯曲身体还可以具有一定的高度。但是重点是——从来没人做过!蜈蚣机器人够酷、够怪、够有趣!

让“蜈蚣”蠕动起来:双伺服旋转的腿

为实现“蜈蚣”的移动,同时考虑到电力需求,Adimin设计了腿在水平和垂直方向上的旋转功能,分别命名为hip servo 和ankle servo。

于是,腿就能在两个方向上蠕动起来!

此处的所有伺服均由PCA9685 PWM分支板控制——这是一个I2C器件,允许同时控制多达16个伺服器,既便宜又实用。

考虑腿的数量和“蜈蚣”身体的的连接方式,Adimin小哥将主体平台部分设计得较大,给腿的添加留出更多空间;同时在前后两端采取铰链设计(采用金属齿轮MG 996R),不仅能实现身体长度的延伸,还能完成向上弯曲的动作。

“蜈蚣”弯曲起来!

用Python制作多足机器人

“蜈蚣”运动的控制代码是一个分层的类结构。

最基本的单元是Servo部分,使用这部分功能可以直接控制伺服器。

代码中更高级的部分是Leg,其中包含了两个Servo对象,分别用来控制之前提到的 “hip” 和 “ankle” 伺服系统,根据其自身leg_index(2*leg_index和2*leg_index + 1)为它们分配正确的板索引值。

LegPair部分与之Leg类似类似,其中创建了两个Leg对象分别控制左右。

1. b = DriverBoard(args.addr, 16)2.3. ifargs.N_pairs > 4:4. b_front = DriverBoard(40, 8)5.6. pairs = []7. for i in range(args.N_pairs):8. if i < 4:9. lp = LegPair(b, i)10. else:11. lp = LegPair(b_front, i-4)12.13. pairs.append(lp)14.15. start = time()16. while True:17. forp in pairs:18. p.increment_ankles()

让我们来看看这段代码的功能——“蜈蚣”弹跳起来了!

其实,让“蜈蚣”实现行走的部分是increment _ankles()函数。为了解释这一点,让我们回到Servo class。

伺服系统的主要工作是循环移动。为了控制伺服装置的位置,需要向它发送一个特定占空比的脉宽调制(PWM)信号。接下来,我们要找到对应于该点的脉宽调制,即中点脉宽调制(mid_pwm),使它围绕一个点振荡。然后,定义一个脉宽调制幅度(pwm_amplitude),该幅度会决定它在这个循环中相对于中点上下移动的距离。于是,让“蜈蚣”循环移动起来只需通过以下代码:

pwm = int(self.pwm_mid + pwm_amplitude*sin(self.phase + self.phase_offset))

如果要让一条腿以我们预期的“行走”方式运动,hip和ankle伺服系统不可能做完全相同的运动。让我们将运动参数化成x和y,加上时间变量t,构成一个正弦函数,令x(t)=y(t)=sin(ωt),便可以得到下面这个运动曲线:

为了实现行走,则还需要您给其中一个变量提供相位偏移(如上面的代码所示),最终得到一个圆。

在伺服系统的相位偏移变量设计中,Adimin表示分层设置实在是太炫酷了——它能使多条腿连贯运动!

每个腿的伺服对象之间需要一定的相位偏移,而每条腿相对于其他腿也存在相位偏移。因此,我们需要给每个LegPair对象一个高级的相位偏移量,然后每个部分将相应的偏移量分配给它的低级对象。

除了上下跳动以外,Python还能实现“蜈蚣”的其他运动方式:

1. b = DriverBoard(args.addr, 16)2.3. ifargs.N_pairs > 4:4. b_front = DriverBoard(40, 8)5.6. sleep(0.5)7. pairs = []8. for i in range(args.N_pairs):9. if i < 4:10. lp = LegPair(b, i)11. else:12. lp = LegPair(b_front, i-4)13.14. if i%2 == 1:15. lp.set_phase_offset(pi)16. pairs.append(lp)17.18. start = time()19. time_limit = args.runtime20.21. while True:22. forp in pairs:23. p.increment()

自然生物学为机器人设计提供了黄金标准,我们需仍要很长时间才能制造出完成一切动物行为动作的多足机器人。而另一方面,机器人不受生物学的限制,这意味着它们总有可能学习动物天生就不会的新行为。

php判断当前是 http还是 https

** * 判断是否SSL协议
 * @return boolean */
function is_ssl() 
{ 
if(isset($_SERVER['HTTPS']) && ('1' == $_SERVER['HTTPS'] || 'on' == strtolower($_SERVER['HTTPS']))){
 return true; 
}elseif(isset($_SERVER['SERVER_PORT']) && ('443' == $_SERVER['SERVER_PORT'] )) { return true; 
} 
return false; 
}

使用

$http = 'http://'; $http =is_ssl()?'https://':$http;

Android Studio 提示Error running app: No Android facet found for app

错误解决办法如下:

可以通过以下几个步骤解决该问题: 

1) 点击菜单File -> 选择Project Structure, 或使用快捷键 (Ctrl+Alt+Shift+S) 打开”Project Structure”.

2) 然后选择”Project Settings” 下的”Facets” 栏

3) 在点击 “+” 号在第二栏的上面用来添加新的facets.

4) 通过”Add “菜单选择”Android” facet从那里会打开另一个对话框来 选择一个module. (选择一个你想要应用的facet)。

5)选择好之后就完成了!明星效应。很简单,在一个领域保持顶尖水平,比在一两个领域保持领先水平和五六个领域保持一般水准都要更有价值、并且收益更好。 有悖常识的真相:让未来更开放的方式,正是专注的去做好一件事情。这个世界上最成功的人,他们在某一领域获得成功之后,可通过经营杠杆进入任何他们想要涉足的领域。而这都得依赖于他们曾极致的专注在做好一件事情上。

报错:The Apache Tomcat installation at this directory is version 8.5.27. A Tomcat 8.0 installation is

今天在eclipse中配置tomcat时,遇到了一个报错,如下所示:

  这里我的Tomcat的版本是8.5.27,报这个错的原因是ellipse里面限制Tomcat的最高版本是8.0的,我用的tomcat的版本明显高于eclipse的要求;具体的改法如下:

  1.首先找到Tomcat的本地安装路径;

  2.然后找到lib文件夹中的Catalina.jar包,用解压软件打开这个jar包;

  3.依次找到并且双击打开catalina.jar\org\apache\catalina\util\ServerInfo.properties文件,如下所示:

  4.将文件中server.info=Apache Tomcat/8.5.27中的8.5.27改成8.0.0即可;

修改完成后重新配置Tomcat不在报错

  修改完成!

thinkphp5 join使用注意

A表有id,name,time等字段,
B表有id,type,uid,email,address等字段。
A表中的id和B表中的uid对应。

    Db::table(A表)->alias('a')
                ->join('B表 b', 'a.id = b.uid')
                ->find();

这样是把B表中的所有字段都给返回了,B表的字段会覆盖A中的同名字段,
比如最终返回的结果中id是B表中的id

这时要注意指定字段->field(‘a.*,b.email,b.adderss’)