php中主要的socket函数语法和使用实例详解

在实际开发中,如果想要创建基于socket的应用程序,就需要详细了解socket的操作方法,要是像了解并熟练使用这些操作方法,就需要先了解php中的各种socket函数。在上一章节中我们详细介绍了php中的socket是什么?这里就介绍一下php中的socket函数。socket函数在php中有几十个之多,这里列举一些主要的socket函数来介绍一下。

它们的语法格式参数如下:

1. socket_create

socket_create ( int $domain , int $type , int $protocol )

此函数用于创建一个socket,它有三个参数,返回值是一个句柄(资源)。

$domain 指定创建socket时使用的通信协议族,其可选的值为:

AF_INET: 基于IPv4的Internet协议

AF_INET6:基于IPv6的Internet协议

AF_UNIX:UNIX本地通信协议

$type 指定socket通信的交互类型,其可选的值为:

SOCK_STREAM:提供序列化的、可靠的、全双工的、基于连接的字节流传输,支持TCP

SOCK_DGRAM:提供数据报式的、无连接的、固定最大长度的、自动寻址功能的传输,支持UDP

SOCK_SEQPACKET:提供序列化的、可靠的、双通道的、基于连接的数据报传输

SOCK_RAW:提供原始的网络访问协议,可手工构建特殊协议类型的套接字,支持ICMP请求(如 ping)

SOCK_RDM:提供可靠的数据报传输,无法保证顺序

$protocol 指定socket使用哪种具体的传输协议,包括ICMP、UDP、TCP,常量SOL_UDP对应UDP,常量SOL_TCP对应常量TCP。

2. socket_bind

socket_bind ( resource $socket , string $address [, int $port = 0 ] )

此函数用于将IP地址和端口绑定到socket_create创建的句柄中,有三个参数,返回布尔值。

$socket 是必选参数,代表socket_create函数创建的句柄

$address 是必选参数,代表要绑定的IP地址

$port 是可选参数,代表要绑定的端口号,指定哪个端口用来监听socket连接,当socket_create函数的第一个参数为AF_INET时,需要指定这个参数。

3. socket_listen

socket_listen ( resource $socket [, int $backlog = 0 ] )

该函数用于监听即将接入的socket连接,仅当socket的交互类型为SOCK_STREAM或SOCK_SEQPACKET时可

用,它有两个参数,返回布尔值。

$socket 是必选参数,代表socket_create函数创建的句柄(且已绑定了主机)

$backlog 是可选参数,表示队列中等候处理的(允许积压的)最大连接数。

4. socket_set_block

socket_set_block ( resource $socket )

该函数用于将socket句柄设置为阻塞模式,只有一个必选参数,返回布尔值。它可以将非阻塞模式的socket转换为阻塞模式。

当在一个阻塞模式的socket中执行某种操作(receive、send、connect、accept等)时,脚本将暂停执行,直到它收到一个信号或它完成了该操作。

$socket 是必选参数,代表一个有效的socket句柄(被socket_create或socket_accept创建的)。

说明一下阻塞模式非阻塞模式的区别:

非阻塞是指函数操作在不能立刻得到结果之前,不会阻塞当前的线程,而会立即返回。而阻塞是指干不完就不准回来,必须得到对方的回应后才能继续下一步操作。特别是当用户比较多时,设置成非阻塞是很必要的。如果是阻塞模式,若两个客户端同时连接上,服务器端在处理一个客户端请求时,另外一个客户端的请求就会被阻塞,只有等到前一个客户端的事情处理完了之后,后一个客户端的请求才会被响应。

5. socket_write

socket_write ( resource $socket , string $buffer [, int $length = 0 ] )

该函数用于向socket中写入指定大小的缓冲数据,有三个参数,返回写入的数据的字节数。

$socket 是必选参数,代表一个有效的socket句柄。

$buffer 是必选参数,指定要写入的字符串数据。

$length 是可选参数,指定轮流写入socket中的数据的字节数,如果它的值大于$buffer的字节数,它会静默地截取至$buffer的字节数长度。

6. socket_read

1
socket_read ( resource $socket , int $length [, int $type = PHP_BINARY_READ ] )

该函数用于从socket中读取指定字节长度的数据,有三个参数,返回读取的字符串数据。

$socket 是必选参数,代表一个有效的socket句柄。
$length 是必选参数,指定读取的字节长度。

$type 是可选参数,默认值为PHP_BINARY_READ,即安全读取二进制数据;另一个可选的值为PHP_NORMAL_READ,表示当遇到 \r 或 \n 时,停止读取。

7. pfsockopen

1
pfsockopen ( string $hostname [, int $port = -1 [, int &$errno [, string &$errstr [, float $timeout = ini_get("default_socket_timeout") ]]]] )

该函数用于实现一个持久的socket连接,即长连接,返回一个句柄。它与 fsockopen 的区别在于,pfsockopen 建立的连接,在脚本执行完毕后,并不会断开。

8. socket_set_option

1
socket_set_option ( resource$socket , int$level , int$optname , mixed$optval )

该函数用于设置socket的控制选项,有四个参数,返回布尔值。

$socket 是必选参数,代表一个有效的socket句柄。

$level 是必选参数,指定option起作用的协议级别,一般取常量 SOL_SOCKET。

$optname 是必选参数,指定要控制的选项名称。

$optval 是必选参数,指定选项的值。

9. socket_last_error

1
socket_last_error ([ resource$socket ] )

该函数用于获取任何socket函数产生的最后错误代号,返回值为整型。

10. socket_strerror

1
socket_strerror ( int $errno )

该函数用于获取错误代号代表的错误描述,返回值为字符串。

以上所有的函数都是PHP中关于socket的,使用这些函数,你必须把你的socket打开,如果你没有打开,请编辑你的php.ini文件,去掉下面这行前面的注释:

1
extension=php_sockets.dll

如果你不知道你的socket是否打开,那么你可以使用phpinfo()函数来确定socket是否打开。

下面通过创建一个服务端和客户端的例子来说明这些函数的用法:

  1. 服务器端
</div>
<div class="line number1 index0 alt2"><code class="php plain"><?php</code></div>
<div class="line number2 index1 alt1"><code class="php comments">//确保在连接客户端时不会超时</code></div>
<div class="line number3 index2 alt2"><code class="php plain">set_time_limit(0);</code></div>
<div class="line number4 index3 alt1"><code class="php variable">$ip</code> <code class="php plain">= </code><code class="php string">'127.0.0.1'</code><code class="php plain">;</code></div>
<div class="line number5 index4 alt2"><code class="php variable">$port</code> <code class="php plain">= 1935;</code></div>
<div class="line number6 index5 alt1"><code class="php comments">/*</code></div>
<div class="line number7 index6 alt2"><code class="php spaces"> </code><code class="php comments">+-------------------------------</code></div>
<div class="line number8 index7 alt1"><code class="php spaces"> </code><code class="php comments">*    @socket通信整个过程</code></div>
<div class="line number9 index8 alt2"><code class="php spaces"> </code><code class="php comments">+-------------------------------</code></div>
<div class="line number10 index9 alt1"><code class="php spaces"> </code><code class="php comments">*    @socket_create</code></div>
<div class="line number11 index10 alt2"><code class="php spaces"> </code><code class="php comments">*    @socket_bind</code></div>
<div class="line number12 index11 alt1"><code class="php spaces"> </code><code class="php comments">*    @socket_listen</code></div>
<div class="line number13 index12 alt2"><code class="php spaces"> </code><code class="php comments">*    @socket_accept</code></div>
<div class="line number14 index13 alt1"><code class="php spaces"> </code><code class="php comments">*    @socket_read</code></div>
<div class="line number15 index14 alt2"><code class="php spaces"> </code><code class="php comments">*    @socket_write</code></div>
<div class="line number16 index15 alt1"><code class="php spaces"> </code><code class="php comments">*    @socket_close</code></div>
<div class="line number17 index16 alt2"><code class="php spaces"> </code><code class="php comments">+--------------------------------</code></div>
<div class="line number18 index17 alt1"><code class="php spaces"> </code><code class="php comments">*/</code></div>
<div class="line number19 index18 alt2"><code class="php comments">/*----------------    以下操作都是手册上的    -------------------*/</code></div>
<div class="line number20 index19 alt1"><code class="php keyword">if</code><code class="php plain">((</code><code class="php variable">$sock</code> <code class="php plain">= socket_create(AF_INET,SOCK_STREAM,SOL_TCP)) < 0) {</code></div>
<div class="line number21 index20 alt2"><code class="php spaces">    </code><code class="php functions">echo</code> <code class="php string">"socket_create() 失败的原因是:"</code><code class="php plain">.socket_strerror(</code><code class="php variable">$sock</code><code class="php plain">).</code><code class="php string">"\n"</code><code class="php plain">;</code></div>
<div class="line number22 index21 alt1"><code class="php plain">}</code></div>
<div class="line number23 index22 alt2"><code class="php keyword">if</code><code class="php plain">((</code><code class="php variable">$ret</code> <code class="php plain">= socket_bind(</code><code class="php variable">$sock</code><code class="php plain">,</code><code class="php variable">$ip</code><code class="php plain">,</code><code class="php variable">$port</code><code class="php plain">)) < 0) {</code></div>
<div class="line number24 index23 alt1"><code class="php spaces">    </code><code class="php functions">echo</code> <code class="php string">"socket_bind() 失败的原因是:"</code><code class="php plain">.socket_strerror(</code><code class="php variable">$ret</code><code class="php plain">).</code><code class="php string">"\n"</code><code class="php plain">;</code></div>
<div class="line number25 index24 alt2"><code class="php plain">}</code></div>
<div class="line number26 index25 alt1"><code class="php keyword">if</code><code class="php plain">((</code><code class="php variable">$ret</code> <code class="php plain">= socket_listen(</code><code class="php variable">$sock</code><code class="php plain">,4)) < 0) {</code></div>
<div class="line number27 index26 alt2"><code class="php spaces">    </code><code class="php functions">echo</code> <code class="php string">"socket_listen() 失败的原因是:"</code><code class="php plain">.socket_strerror(</code><code class="php variable">$ret</code><code class="php plain">).</code><code class="php string">"\n"</code><code class="php plain">;</code></div>
<div class="line number28 index27 alt1"><code class="php plain">}</code></div>
<div class="line number29 index28 alt2"><code class="php variable">$count</code> <code class="php plain">= 0;</code></div>
<div class="line number30 index29 alt1"><code class="php keyword">do</code> <code class="php plain">{</code></div>
<div class="line number31 index30 alt2"><code class="php spaces">    </code><code class="php keyword">if</code> <code class="php plain">((</code><code class="php variable">$msgsock</code> <code class="php plain">= socket_accept(</code><code class="php variable">$sock</code><code class="php plain">)) < 0) {</code></div>
<div class="line number32 index31 alt1"><code class="php spaces">        </code><code class="php functions">echo</code> <code class="php string">"socket_accept() failed: reason: "</code> <code class="php plain">. socket_strerror(</code><code class="php variable">$msgsock</code><code class="php plain">) . </code><code class="php string">"\n"</code><code class="php plain">;</code></div>
<div class="line number33 index32 alt2"><code class="php spaces">        </code><code class="php keyword">break</code><code class="php plain">;</code></div>
<div class="line number34 index33 alt1"><code class="php spaces">    </code><code class="php plain">} </code><code class="php keyword">else</code> <code class="php plain">{</code></div>
<div class="line number35 index34 alt2"><code class="php spaces">        </code></div>
<div class="line number36 index35 alt1"><code class="php spaces">        </code><code class="php comments">//发到客户端</code></div>
<div class="line number37 index36 alt2"><code class="php spaces">        </code><code class="php variable">$msg</code> <code class="php plain">=</code><code class="php string">"测试成功!\n"</code><code class="php plain">;</code></div>
<div class="line number38 index37 alt1"><code class="php spaces">        </code><code class="php plain">socket_write(</code><code class="php variable">$msgsock</code><code class="php plain">, </code><code class="php variable">$msg</code><code class="php plain">, </code><code class="php functions">strlen</code><code class="php plain">(</code><code class="php variable">$msg</code><code class="php plain">));</code></div>
<div class="line number39 index38 alt2"><code class="php spaces">        </code></div>
<div class="line number40 index39 alt1"><code class="php spaces">        </code><code class="php functions">echo</code> <code class="php string">"测试成功了啊\n"</code><code class="php plain">;</code></div>
<div class="line number41 index40 alt2"><code class="php spaces">        </code><code class="php variable">$buf</code> <code class="php plain">= socket_read(</code><code class="php variable">$msgsock</code><code class="php plain">,8192);</code></div>
<div class="line number42 index41 alt1"><code class="php spaces">        </code></div>
<div class="line number43 index42 alt2"><code class="php spaces">        </code></div>
<div class="line number44 index43 alt1"><code class="php spaces">        </code><code class="php variable">$talkback</code> <code class="php plain">= </code><code class="php string">"收到的信息:$buf\n"</code><code class="php plain">;</code></div>
<div class="line number45 index44 alt2"><code class="php spaces">        </code><code class="php functions">echo</code> <code class="php variable">$talkback</code><code class="php plain">;</code></div>
<div class="line number46 index45 alt1"><code class="php spaces">        </code></div>
<div class="line number47 index46 alt2"><code class="php spaces">        </code><code class="php keyword">if</code><code class="php plain">(++</code><code class="php variable">$count</code> <code class="php plain">>= 5){</code></div>
<div class="line number48 index47 alt1"><code class="php spaces">            </code><code class="php keyword">break</code><code class="php plain">;</code></div>
<div class="line number49 index48 alt2"><code class="php spaces">        </code><code class="php plain">};</code></div>
<div class="line number50 index49 alt1"><code class="php spaces">        </code></div>
<div class="line number51 index50 alt2"><code class="php spaces">    </code></div>
<div class="line number52 index51 alt1"><code class="php spaces">    </code><code class="php plain">}</code></div>
<div class="line number53 index52 alt2"><code class="php spaces">    </code><code class="php comments">//echo $buf;</code></div>
<div class="line number54 index53 alt1"><code class="php spaces">    </code><code class="php plain">socket_close(</code><code class="php variable">$msgsock</code><code class="php plain">);</code></div>
<div class="line number55 index54 alt2"><code class="php plain">} </code><code class="php keyword">while</code> <code class="php plain">(true);</code></div>
<div class="line number56 index55 alt1"><code class="php plain">socket_close(</code><code class="php variable">$sock</code><code class="php plain">);</code></div>
<div class="line number57 index56 alt2"><code class="php plain">?></code></div>
<div>
<?php
error_reporting(E_ALL);
set_time_limit(0);
echo "<h2>TCP/IP Connection</h2>\n";
$port = 1935;
$ip = "127.0.0.1";
/*
 +-------------------------------
 *    @socket连接整个过程
 +-------------------------------
 *    @socket_create
 *    @socket_connect
 *    @socket_write
 *    @socket_read
 *    @socket_close
 +--------------------------------
 */
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if ($socket < 0) {
    echo "socket_create() failed: reason: " . socket_strerror($socket) . "\n";
}else {
    echo "OK.\n";
}
echo "试图连接 '$ip' 端口 '$port'...\n";
$result = socket_connect($socket, $ip, $port);
if ($result < 0) {
    echo "socket_connect() failed.\nReason: ($result) " . socket_strerror($result) . "\n";
}else {
    echo "连接OK\n";
}
$in = "Ho\r\n";
$in .= "first blood\r\n";
$out = '';
if(!socket_write($socket, $in, strlen($in))) {
    echo "socket_write() failed: reason: " . socket_strerror($socket) . "\n";
}else {
    echo "发送到服务器信息成功!\n";
    echo "发送的内容为:<font color='red'>$in</font> <br>";
}
while($out = socket_read($socket, 8192)) {
    echo "接收服务器回传信息成功!\n";
    echo "接受的内容为:",$out;
}
echo "关闭SOCKET...\n";
socket_close($socket);
echo "关闭OK\n";
?>

如何查看已安装的CentOS版本信息

如何查看已安装的CentOS版本信息

1)[root@localhost ~]# cat /proc/version

Linux version 2.6.18-194.el5 (mockbuild@builder10.centos.org) (gcc version 4.1.2 20080704 (Red Hat 4.1.2-48)) #1 SMP Fri Apr 2 14:58:14 EDT 2010

2)

[root@localhost ~]# uname -a

Linux localhost.localdomain 2.6.18-194.el5 #1 SMP Fri Apr 2 14:58:14 EDT 2010 x86_64 x86_64 x86_64 GNU/Linux

3)

[root@localhost ~]# uname -r

2.6.18-194.el5

2. 查看linux版本:

1) 列出所有版本信息,

[root@localhost ~]# lsb_release -a

LSB Version:    :core-3.1-amd64:core-3.1-ia32:core-3.1-noarch:graphics-3.1-amd64:graphics-3.1-ia32:graphics-3.1-noarch

Distributor ID: CentOS

Description:    CentOS release 5.5 (Final)

Release:        5.5

Codename:      Final

注:这个命令适用于所有的linux,包括RedHatSUSE、Debian等发行版。

2) 执行cat /etc/issue,例如如下:

[root@localhost ~]# cat /etc/issue

CentOS release 5.5 (Final)

Kernel r on an m

3) 执行cat /etc/redhat-release ,例如如下:

[root@localhost ~]# cat /etc/redhat-release

CentOS release 5.5 (Final)

查看系统是64位还是32位:

1、getconf LONG_BIT or getconf WORD_BIT

[root@localhost ~]# getconf LONG_BIT

64

2、file /bin/ls

[root@localhost ~]# file /bin/ls

/bin/ls: ELF 64-bit LSB executable, AMD x86-64, version 1 (SYSV), for GNU/Linux 2.6.9, dynamically linked (uses shared libs), for GNU/Linux 2.6.9, stripped

3、lsb_release  -a

[root@localhost ~]# lsb_release -a

LSB Version:    :core-3.1-amd64:core-3.1-ia32:core-3.1-noarch:graphics-3.1-amd64:graphics-3.1-ia32:graphics-3.1-noarch

Distributor ID: CentOS

Description:    CentOS release 5.5 (Final)

Release:        5.5

Codename:      Final

4、或者是使用查看文件的方法。

vim /ect/issue

更多CentOS相关信息见CentOS 专题页面 http://www.linuxidc.com/topicnews.aspx?tid=14

本文永久更新链接地址http://www.linuxidc.com/Linux/2014-12/110748.htm

yii2 多条件搜索(like > < <> = ) 打印sql

如何打印sql语句

$products = TProductArt::find()
    - >select(['product_id','art_name','domain','price','final_price','discount_type','discount','art_expiry','image_large'])
    ->where($where)
    ->orderBy('score DESC')
    ->andWhere(['>', 'art_expiry', $after_2_minute])
    ->andWhere(['<', 'art_start', $current_date])
    ->andWhere(['<>', 'image_large',''])
    ->andWhere($search_like)
    ->andWhere($search_price)
    ->limit(20)
    ->createCommand()->getRawSql();


public static function searcharray($search, $domain, $group,$price)
{
    $where = array();
    if(in_array($domain, self::$domainsList)){
        $where['domain']=$domain;
    }
    $search_like=array();
    if ($search!='')
    {
        $search = trim($search);
        $search = preg_replace('!\s+!', ' ', $search);  // replaces multiple space with single space
        $search_like = ['or like', 'art_name',explode(" ", $search)];
    }
    if ($group!='')
    {
        if (in_array($group, Yii::$app->params['amazon_product_groups']))
        {
            $where['art_product_group']=$group;
        }
    }
    $search_price=array();
    if(floatval($price)>0)
    {
        $search_price=['<', 'final_price', $price];
    }
    $where['status']=0;
    $after_2_minute = date('Y-m-d H:i:s', time() + 120);
    $current_date = date('Y-m-d H:i:s', time());
    return $products = TProductArt::find()
        ->select(['product_id','art_name','domain','price','final_price','discount_type','discount','art_expiry','image_large'])
        ->where($where)
        ->orderBy('score DESC')
        ->andWhere(['>', 'art_expiry', $after_2_minute])
        ->andWhere(['<', 'art_start', $current_date])
        ->andWhere(['<>', 'image_large',''])
        ->andWhere($search_like)
        ->andWhere($search_price)
        ->limit(20)
     //   ->createCommand()->getRawSql();
        ->asarray()
        ->all()
    ;


}

BotMan 机器人

About BotMan

BotMan is a framework agnostic PHP library that is designed to simplify the task of developing innovative bots for multiple messaging platforms, including Slack, Telegram, Microsoft Bot Framework, Nexmo, HipChat, Facebook Messenger and WeChat.

$botman->hears('I want cross-platform bots with PHP!', function (BotMan $bot) {
    $bot->reply('Look no further!');
});

Documentation

You can find the BotMan documentation at http://botman.io.

Support the development

Do you like this project? Support it by donating

Contributing

Please see CONTRIBUTING for details.

Security Vulnerabilities

If you discover a security vulnerability within BotMan, please send an e-mail to Marcel Pociot at m.pociot@gmail.com. All security vulnerabilities will be promptly addressed.

License

BotMan is free software distributed under the terms of the MIT license.

php 正则过滤标题 分词 获取前8个单词 且字符长度大于3

/**
 * 通过商品标题返回8个单词关键词标题
 * @param $title
 * @return string
 */
function getTitle($title){
     //去掉中,英文标点符号和HTML代码
    $str=preg_replace('/\s/',' ',preg_replace("/[[:punct:]]/",' ',strip_tags(html_entity_decode(str_replace(array(',','?','!','¥','(',')',':','‘','’','“','”','《','》',',','…','。','、','&nbsp'),'',$title),ENT_QUOTES))));
    //过滤掉重复字符
    $search_terms = explode(" ", $str);
    foreach ($search_terms as $key => $s) {
        $s = trim($s);
        if (strlen($s) > 3) {
            $search_terms[$key] = $s;
        } else {
            unset($search_terms[$key]);
        }
    }
    $search_terms = array_unique($search_terms);
    if(count($search_terms)>8)
    {
        $title=implode(' ', array_slice($search_terms,0,8));
    }
    else
    {
        $title=implode(' ',$search_terms);
    }
    return $title;
}

原标题

iphone 8 7 6s 6 Screen Protector Tempered Glass Film Case Friendly Anti-Scratch Anti-Fingerprint Bubble Free Compatible 3D Touch for Apple iPhone 8 iphone 7 iphone 6s iphone 6 4.7-Inch (2 Pack)

返回标题

iphone Screen Protector Tempered Glass Film Case Friendly

 

YII2项目常用技能知识总结

1、不通过日志获取AR执行的原生SQL语句和打印变量数据

$query = User::find() ->select(['username'])->where(['id'=>[1,2,3,4])
// get the AR raw sql in YII2
$commandQuery = clone $query;
echo $commandQuery->createCommand()->getRawSql();$users = $query->all();
打印变量数据可以这样写:
//引用命名空间
use yii\helpers\VarDumper;
//使用
VarDumper::dump($var);
//使用2  第二个参数是数组的深度  第三个参数是是否显示代码高亮(默认不显示)
VarDumper::dump($var, 10 ,true);

2、从数据库二维数组中返回一维数组并配合rules验证规则实现分类数据过滤。

普通返回表记录的二维数组

Member::find()->select('userid')->asArray()->all();
Array
(
    [0] => Array
        (
            [userid] => 1
        )

    [1] => Array
        (
            [userid] => 2
        )

    [2] => Array
        (
            [userid] => 3
        )

)

返回字段的一维数组

Member::find()->select('userid')->asArray()->column();

或者:

\yii\helpers\ArrayHelper::getColumn(Member::find()->all(), 'userid')
Array
(
    [0] => 1
    [1] => 2
    [2] => 3
)

返回一维数组配合验证规则验证数据正确性,如分类catid正确分为只有1-4,但是在devTools打开修改catid为5,提交同样会到数据库,此时rules验证规则如下:

['catid', 'in', 'range' => category::find()->select('id')->asArray()->column()],

当然,这个也可以通过下面这样子写,一样的:

['catid', 'in', 'range' => \yii\helpers\ArrayHelper::getColumn(category::find()->all(), 'catid')],

这样就可以过滤不正确的分类数据了!

3、友好时间表示方法

之前一直使用自定义的友好时间函数。几天前发现万能的YII已经提供了友好时间访问,代码如下:

Yii::$app->formatter->asRelativeTime('1447565922'); //2小时前

4、使用不同的响应类型或者自定义响应类型

有效的格式:

  • FORMAT_RAW
  • FORMAT_HTML
  • FORMAT_JSON
  • FORMAT_JSONP
  • FORMAT_XML

JSON响应

public function actionIndex()
{
    \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
    $items = ['some', 'array', 'of', 'data' => ['associative', 'array']];
    return $items;
}

返回:

{
    "0": "some",
    "1": "array",
    "2": "of",
    "data": ["associative", "array"]
}

自定义响应格式

让我们创建一个定制的响应格式。例子做点有趣和疯狂的事我返回PHP 数组。 首先,我们需要格式化程序本身。创建 components/PhpArrayFormatter.php:

<?php
namespace app\components;
use yii\helpers\VarDumper;
use yii\web\ResponseFormatterInterface;
class PhpArrayFormatter implements ResponseFormatterInterface
{
    public function format($response)
    {
        $response->getHeaders()->set('Content-Type', 'text/php; charset=UTF-8');
        if ($response->data !== null) {
            $response->content = "<?php\nreturn " . VarDumper::export($response->data) . ";\n";
        }
    }
}

组件配置:

return [
    // ...
    'components' => [
        // ...
        'response' => [
            'formatters' => [
                'php' => 'app\components\PhpArrayFormatter',
            ],
        ],
    ],
];

现在是准备使用。在 controllers/SiteController 创建一个新的方法 actionTest:

public function actionTest()
{
    Yii::$app->response->format = 'php';
    return [
        'hello' => 'world!',
    ];
}

返回如下:

<?php
return [
    'hello' => 'world!',
];

5、AR入库前时间通过在模型重写behaviors方法实现优雅入库方式。

如下:

public function behaviors()
{
    return [
        'timestamp' => [
            'class' => TimestampBehavior::className(),
            'attributes' => [
                ActiveRecord::EVENT_BEFORE_INSERT => 'creation_time',
                ActiveRecord::EVENT_BEFORE_UPDATE => 'update_time',
            ],
            'value' => function() { return date('U'); // unix timestamp },
        ],
    ];
}

6、除配置组件记录不同级别日志外,也可以自定义在某个地方记录LOG日志

use yii\log\Logger;
\Yii::getLogger()->log('User has been created', Logger::LEVEL_INFO);

7、 ActiveForm类不让生成label标签

//方法一,通过ActiveForm类
$form->field($model, '字段名')->passwordInput(['maxlength' => true])->label(false) ?>
//方法二,通过 HTML类
Html::activeInput($type,$model,'字段名')

Yii2给必填项加星,样式如下:

div.required label:after {
    content: " *";
    color: red;
}

8、Yii2 获取接口传过来的 JSON 数据:

接收get和post的数据很容易,那么接收json数据呢?!没关系,看这里:

Yii::$app->request->rawBody;

9、座机和手机号码必须填写一个:

public function rules()
{
    return [
        [['telephone', 'mobile'], function ($attribute, $param) {//至少要一个
            if (empty($this->telephone) && empty($this->mobile)) {
                $this->addError($attribute, 'telephone/mobile至少要填一个');
            }
        }, 'skipOnEmpty' => false],
    ];
}

10、where多条件查询示例:

//and复杂示例:
$time = time();
Member::find()->where(['and', ['userid' => 1, 'company' =>'测试公司'], ['>', 'addtime', $time]]);
//SELECT * FROM `member` WHERE ((`userid`=1) AND (`company`='测试公司')) AND (`addtime` > 1447587486)
//and和or组合示例:
$query = Member::find()->where(['and', ['>','userid',2], ['or', ['company' => '深圳市新民家具有限公司'], ['address' => '深圳']]]);
//SELECT * FROM `member` WHERE (`userid` > 2) AND ((`company`='深圳市新民家具有限公司') OR (`address`='深圳'))

11、关于事务:

优雅的写法

Yii::$app->db->transaction(function() {
    $order = new Order($customer);
    $order->save();
});

这相当于下列冗长的代码:

$transaction = Yii::$app->db->beginTransaction();
try {
    $order = new Order($customer);
    $order->save();
    $transaction->commit();
} catch (\Exception $e) {
    $transaction->rollBack();
    throw $e;
}

12、rest风格API获取客户端提交的get和post的数组

// post
Yii::$app->request->bodyParams
// get
Yii::$app->request->queryParams;

13、一个控制器调用其他控制器action的方法:

方法一:

是经典的重写actions方法

  public function actions()
    {
        return [
            'error' => [
                'class' => 'yii\web\ErrorAction',
            ],
            'captcha' => [
                'class' => 'yii\captcha\CaptchaAction',
                'fixedVerifyCode' => YII_ENV_TEST ? 'testme' : null,
            ],
        ];
    }

actions继承yii\base\Actions类,并重写父类的run方法。

方法二:

site控制器如下,访问MemberController控制器下面的index方法。

class SiteController extends Controller
{
    public function actionIndex(){
     Yii::$app->runAction('member/index', ['param'=>'123']);
    }
}

MemberController控制器如下:

class MemberController extends Controller
{
    public function actionIndex($param = '456'){
     echo "second Controller".$param;
    }
}

访问:http://www.yii.dev/site/index.html

输出:second Controller123

14、点击下载,如下载安卓APK文件。

public function actionDownload(){
    return \Yii::$app->response->setDownloadHeaders("http://xxx.com/apk/com.trade.activity.3.0.8.apk");
    //return \Yii::$app->response->sendFile("./com.trade.activity.3.0.8.apk");
}

15、YII模块IP白名单设置,增加安全性

$config['modules']['gii'] = [
     'class' => 'yii\gii\Module',
     'allowedIPs' => ['127.0.0.1', '::1','10.10.1.*'], 
];
$config['modules']['debug'] = [
    'class' => 'yii\debug\Module',
    'allowedIPs' => ['127.0.0.1', '::1', '192.168.0.*', '192.168.33.1'],
];

16、防止 SQL 和 Script 注入

use yii\helpers\Html;
use yii\helpers\HtmlPurifier;
echo Html::encode($view_hello_str) //可以原样显示<script></script>代码  
echo HtmlPurifier::process($view_hello_str)  //可以过滤掉<script></script>代码

17、验证某个ID值是否存在

//之前一直用$model->findOne($id);exists()方法,资源节约,有没有?!

public function validateAttribute($model, $attribute)
{
   $value = $model->$attribute;
   if (!Status::find()->where(['id' => $value])->exists()) {
       $model->addError($attribute, $this->message);
   }
}

18、批量查询

如查询并循环10000条数据。一次性拿1万条内存会有压力,通过批量查询,每次拿1000条,那么内存始终只有1000条的占有量。

foreach(Member::find()->batch(1000) as $value){
    //do something
    //print_r(count($value));
}

19、关于CSRF验证

方法一:关闭Csrf,除非必要,否则不推荐

public function init(){
    $this->enableCsrfValidation = false;
}

方法二:普通提交,form表单中加入隐藏域

<input name="_csrf" type="hidden" id="_csrf" value="<?= Yii::$app->request->csrfToken ?>">

方法三:ajax异步提交,加入_csrf字段

var csrfToken = $('meta[name="csrf-token"]').attr("content");
$.ajax({
  type: 'POST',
  url: url,
  data: {_csrf:csrfToken},
  success: success,
  dataType: dataType
});

20、YII命令行生成数据库文件

自动列出可用的migrate文件

php yii migrate

从vendor/callmez/wechat/migrations目录下生成数据表

php yii migrate --migrationPath=@callmez/wechat/migrations

从当前应用/migrations/db1下初始化数据到db1表

php yii migrate --migrationPath=@app/migrations/db1 --db=db1

21.关联查询

//客户表Model:CustomerModel 
//订单表Model:OrdersModel
//国家表Model:CountrysModel
//首先要建立表与表之间的关系 
//在CustomerModel中添加与订单的关系
      
Class CustomerModel extends \yii\db\ActiveRecord
{
    ...
    
    public function getOrders()
    {
        //客户和订单是一对多的关系所以用hasMany
        //此处OrdersModel在CustomerModel顶部别忘了加对应的命名空间
        //id对应的是OrdersModel的id字段,order_id对应CustomerModel的order_id字段
        return $this->hasMany(OrdersModel::className(), ['id'=>'order_id']);
    }
     
    public function getCountry()
    {
        //客户和国家是一对一的关系所以用hasOne
        return $this->hasOne(CountrysModel::className(), ['id'=>'Country_id']);
    }
    ....
}
      
// 查询客户与他们的订单和国家
CustomerModel::find()->with('orders', 'country')->all();

// 查询客户与他们的订单和订单的发货地址
CustomerModel::find()->with('orders.address')->all();

// 查询客户与他们的国家和状态为1的订单
CustomerModel::find()->with([
    'orders' => function ($query) {
        $query->andWhere('status = 1');
        },
        'country',
])->all();

22、yii2中关闭debug后return $this->redirect($url);不能跳转,服务器报500错误。

问题分析:

1.必须 return 才能让$this->redirect($url);立马跳转, 而不执行后续代码;

2.redirect() 中指定了响应的 http status code,默认是302;

3.当执行$this->redirect($url)时,不管是否在后面加return false 、return true都没有用,还是继续执行完代码。使用header(“Location:$url”);exit;可以解决此问题,但是,这不是yii2的逻辑,并不完美。

解决办法:

【本文由php_sir的博客 http://blog.sina.com.cn/phpsir原创,未经授权禁止转载】

1.在正常情况下,使用 return $this->redirect($url);

2.在解决方案1不生效时,用$this->redirect($url);Yii::$app->response->send();

3.在解决方案2不生效时,用$this->redirect($url);Yii::$app->end();

总结:

用Yii::$app->end();、Yii::$app->response->send();不管在actionXXX还是init方法都能终止代码,而return只能在action终止代码,是因为在init()里仅仅是代码的执行,return只是代码返回。

https://www.cnblogs.com/sandea/p/5714830.html

LNMP 1.4教程及注意事项和多PHP版本使用教程

LNMP 1.x版本基本都可以正常升级到1.4使用1.4的管理脚本和新的功能。

升级管理脚本:wget -c http://soft.vpser.net/lnmp/lnmp1.4.tar.gz && tar zxf lnmp1.4.tar.gz && cd lnmp1.4 && ./upgrade1.x-1.4.sh
有些功能是需要另外升级nginx、php版本或安装多php版本的,下面会进行单独的说明。

新的功能主要是两个添加SSL和多PHP版本选择。

添加SSL:

添加SSL有两种方式可以选择,1是自备证书和key,这个不需要多说,按提示分别填写上证书和key的完整路径和名称。2是使用Let’sEncrypt生成3个月有效期的SSL证书,另外按提示一个邮箱就可以。

已经添加过改域名的http站点,添加https站点直接运行:lnmp ssl add 按提示添加,可以参考新添加教程的提示说明。

新添加虚拟主机按:https://lnmp.org/faq/lnmp-vhost-add-howto.html

注意1:添加的SSL虚拟主机是默认http2的,如果是之前的版本未使用openssl 1.0.2进行编译或者Nginx低于1.9的话,建议升级到1.12.0,使用升级脚本:./upgrade.sh nginx 进行升级。
注意2:如果是对已有主机添加SSL,因为之前的1.3版本默认LNMP的虚拟主机里是禁止 . 开头的隐藏文件及目录的,所以访问http://abc.com/.well-known/acme-challenge/**** 这个链接的话返回403错误,所以必须要将对应虚拟主机配置文件里的
location ~ /\.
{
deny all;
}
这段配置删掉或注释掉或在这段配置前面加上
location ~ /.well-known {
allow all;
}
修改保存后重启nginx。
注意3:https网站里面的js、css、图片等资源的引用必须是https的,如果是http的会提示不安全也没有小绿锁。需要自行修改网站模板、网站内容里的图片等为https连接或者直接使用相对路径引用。

多PHP版本使用教程:
多PHP版本只支持LNMP模式,LNMPA、LAMP模式下不支持!
要使用多PHP先安装多PHP版本,在lnmp1.4源码目录下运行:./install.sh mphp 按提示选择要另外安装的PHP版本,不能多选,只能选一个,要安装多个需要安装完成后再运行前面的安装命令。
已经升级完LNMP管理脚本且已安装好多PHP版本的话,lnmp vhost add 时会在设置完日志名称后提示当前已经存在的PHP版本,按提示的数字选择就可以。

如果已经存在的虚拟主机要更改PHP为指定版本需要修改虚拟主机的配置文件,配置文件为 /usr/local/nginx/conf/vhost/域名.conf ,将里面的include enable-php.conf; 替换为 include enable-php7.1.conf; 前面的7.1为php版本,可以根据自己的需要进行修改,但必须要对应的多php版本已经安装,要不然会提示502错误。

修改后必须要重启nginx,否则无法生效。

如要使用新版里面的PHP模块组件安装工具需要升级一下PHP才能使用新版PHP组件安装工具。

多PHP版本PHP模块/组件
多PHP模块安装依然和以前一样只不过存在多PHP版本时会让你选择为哪个版本的PHP安装PHP模块/组件,教程参考:https://lnmp.org/faq/addons.html

 

https://lnmp.org/faq/upgrade1-4.html