php 获取当前浏览器语言 EN CN

/*获取客户端语言设置到session*/
public function clientLang()
{
    $languageValue = Yii::$app->session->get('language');
    if (!isset($languageValue))
    {
        //只取前4位,这样只判断最优先的语言。如果取前5位,可能出现en,zh的情况,影响判断。
        $lang = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 4);
        if (preg_match("/zh-c/i", $lang)||preg_match("/zh/i", $lang))
            Yii::$app->session['language'] ='CN';
        else
            Yii::$app->session['language'] ='EN';
    }


}

Composer实现PHP中类的自动加载

本篇博客承接上一篇,学习一下Composer实现的PHP的类的自动加载方式。首先说明一下,Composer是PHP针对PHP语言的第三方的依赖管理工具,将工程所用到的依赖文件包含在composer.json文件中,使用composer install命令就可以将所使用对应库或者文件加载进工程里面。下面分两部分介绍composer的基础,分别是composer的依赖管理和自动加载。

依赖管理

在composer出现之前,如果咋PHP项目中需要第三方的依赖文件,则需要程序员将所需要的源代码拷贝进工程中或者将源代码对应的文件下载下来手动添加到工程中。如果所需要的依赖文件依赖于更多的第三方文件,则程序员会陷入拷贝依赖文件的黑洞中,费时费力不说,有可能还会出现一些失误,composer就是在这种情况下出现的用于减轻程序员的对于依赖管理的负担的工具。

Composer通过使用配置文件composer.json文件完成依赖管理。composer.json文件包含了项目的简单介绍、项目对于外界的库或文件的依赖。从composer.json的扩展名就可以看得出来,composer.json中的内容是按照json标准组织的。本篇博客集中在类的自动加载机制上,因此对于composer.json中关于项目的作者等相关信息的解释忽略不解释。

在composer中将本项目所需要的外部依赖包写在关键字require对应的值中,require键可以对应着多个所需要的包,各个不同的包之间用逗号分隔。假设项目需要一个外部依赖包monolog,下面是在compose.json文件中对于monolog包的依赖配置项:

1
2
3
4
5
{
    "require":{
        "monolog/monolog": "1.0.* @dev"
    }
}

如上所示,require关键字将会映射包的名称monolog和包的版本1.0.*。其中,包的名称有两部分组成,中间以“/”分隔,“/”之前代表的包的所有者,在Github上一般是代表的Github的用户名,“/”代表的是实际的包的名称。其中“/”之前的名称必须是唯一的,但是”/”之后的包的名称是可以存在重复的,例如“Jack/monolog”和“monolog/monolog”是可以共存的。而后面的”1.0.*”代表的是所依赖的包的版本,其中“*”代表的是“1.0”之下的任意一个版本,例如:1.0.1,1.0.2或者1.0.9等等。“@dev”代表了可以获取该包的开发版本。默认情况下,composer将获取所需要的包的最新的稳定版本,而不会考虑开发版本,因为开发版本一般是不太稳定的版本。但是,如果确定开发版本没有什么问题就可以加上“@dev”以允许获取开发的版本。如果没有加上“@dev”,而除了开发版本之外不存在别的版本的话,则composer加载依赖项出错。

在composer中配置好依赖的第三方的包之后,就可以使用composer install命令获取第三方的包了。运行成功之后就可以项目中就会出现vendor文件夹,vendor文件夹中会包含我们在require中所列出的monolog文件。

出了生成列在composer.json中关键字require值下的文件之外,成功运行composer install之后还会生成对应的composer.lock文件,该文件依据composer.json中的依赖项生成依赖包对应的版本。这里需要说明的是,在我们运行composer install的时候会首先判断是否存在着composer.lock文件。如果原本就存在这composer.lock文件,那么就会直接根据composer.lock中的版本下载对应的包,此时不再理会composer.json中的配置项。如果不存在composer.lock文件,则根据composer.json文件中的配置下载对应的版本,并生成composer.json对应的composer.lock文件。composer.lock又称为锁定文件,生成对应的composer.lock之后,composer.json和composer.lock共同对版本进行控制。有了composer.lock之后,及时有了新的版本也不会触发新版本的更新,除非手动使用composer update命令进行手动的更新。

开发环境下的依赖

  有的时候我们只是在开发的时候才会依赖于某个具体的包,但是在发行的版本中并不需要这样的包,为了达到这种要求可以使用require-dev引入开发环境下的包依赖。如下:

1
2
3
4
5
{
    "require-dev":{
        "xxxx/xxxx": "x.x.* @dev"
    }
}

自动加载类

通过composer.json或者composer.lock,所依赖的第三方库已经被下载下来了,那么在我们的项目中怎么使用这些第三方库呢?最简单的方式就是通过include或者require将所需要的类文件包含进来,但是这种方式需要我们自己去寻找所使用的类对应的类文件,这就存在和PHP语言中直接使用include和require加载所需要的类存在同样的弊端,一种比较简单的方式当然就是使用composer提供的类的自动加载机制了。类似于PHP的自动加载机制,composer提供了autoload实现类的自动加载。

成功运行composer install之后,只要调用生成的vendor目录下的autoload.php文件就可以调用通过composer.json加载的类了。以上面所述的项目中需要monolog包为例,通过可以通过下面的方式使用monolog包中的Logger类。

1
2
include "vendor/autoload.php";
$log = new Monolog\Logger("name");

当然,除了使用第三方库中提供的类之外,还可以使用自己的定义的类。Composer提供了autoload关键字用于加载我们自己提供的类,假如我们定义了一个有关测试的类,如下:

1
2
3
4
5
6
7
class ClassTest{
    public function test()
    {
        echo "hello world!";
    }
}

将该类放在lib目录下的ClassTest.php文件夹下面,那么怎么让composer加载自己定义的类呢?

1. 在composer.json中加入autoload关键字

1
2
3
"autoload":{
    "files":["lib/ClassTest.php"];
}

files键对应的值是一个数组且改值是相对于文件应用根目录的文件的路径。在composer.json中加入上述的关键字之后,在命令行下运行composer dump-autoload就可以让composer重建加载信息,那么就可以在其他的文件中使用这个类了。

上述所述的方法和PHP中直接使用include和require存在一样的弊端,每个类都需要重新书写加载文件,费时费力。

2. composer.json中加入classmap关键字

相比于每个类文件都需要加载一次的做法,使用classmap关键字,能够减少程序员的负担,只需要将文件所在的目录添加在classmap的值中即可,如下:

1
"classmap" : ["lib"]

其实这需要建立一种类名到类所在的文件的映射关系。当需要相应的类的时候,composer通过类名找到对应的类文件名,将相应的类include进来。但是这同样存在一个问题就是,每增加一个类都需要重新运行一次composer dump-autoload重新创建类名到文件之间的映射关系,从而将对应的类加载进来。虽然比files关键字节省了功夫,但是依然不能完全自动加载所需要的类。

3. 基于PHP规范的自动加载方式

  针对PHP这种编程语言,到目前FIG指定了五个规范,分别如下:

  • PSR0:自动加载;
  • PSR1:基本代码规范;
  • PSR2:代码样式规范;
  • PSR3:日志接口规范;
  • PSR4:自动加载规范;

看上去PSR4与PSR0是重复了,但是PSR4规范比较干净,可以看成PSR0规范的升级版。二者最重要区别在于:PSR0规范中,下划线会被转换为目录分隔符,但是PSR4中下划线不具有特殊的含义。二者都是通过特定的目录、文件名以及类名,实现快速查找到类文件,并将相应的类加载进来。

PSR0和PSR4要求有个命名的空间,对上述的ClassTest类做相应的修改如下:

1
2
3
4
5
6
7
8
9
<?php
namespace ClassTestLib;
class ClassTest{
    public function test()
    {
        echo "hello world!";
    }
}

那么对应的文件的路径应该改为\lib\ClassTestLib\ClassTest.php,此时修改composer.json中的autoload如下:

1
2
3
4
5
"autoload":{
    "psr-0":{
        "ClassTestLib":"lib/"
    }  
}

可能你发现psr0的值有一些奇怪,是的。在这里ClassTestLib代表的是命名空间,而”lib”是目录名。加载对应的类文件的时候,搜索的路径是lib/ClassTestLib,而不是ClassTestLib/lib,这是在书写composer.json的时候需要注意的一点。

如果命名空间中存在着“\”,则在书写对应的composer.json的时候需要在相应的“\”再添加一个“\”。例如,如果命名空间改为ClassTest\Lib,相应的对应与应用根目录的路径名称应该变为\lib\ClassTest\Lib\ClassTest.php,对应的composer.json中的autoload应该变为:

1
2
3
4
5
"autoload":{
    "psr-0":{
        "ClassTest\\Lib":"lib/"
    }  
}

 

小结:以上是关于composer的基本使用方法,后续在遇到相关的问题,和大家在一起学习。

关于GMT和UTC时间? php 关于时区 date gmdate date_default_timezone_set/get 终极答疑

关于GMT和UTC时间?

GMT+0800
Greenwich: [gri:nitf], 格林威治/格林尼治.是英国伦敦泰晤士河附近的一个小镇
Mean: adj. 自私的; n. 平均..
he is mean about money.
GMT就是格林威治平均/标准时间

什么叫本初子午线?

国外叫 : prime mer’idian.只是在中国内才叫本初-子午线. 只是国内的翻译这样怪怪的.
prime 被国人翻译为本初,
meridian本意是 经线的/全盛的, 顶点的:
he is “at the meridian of ” life.
he was “at the meridian of ” his power then.
而在中国, 子为北方, 午为南方, 子午即南北方向, 所以就把经线 “南北线” 翻译成了子午线.
因此, 子午线只是中国的叫法, 国外没有 “子午” 这种天干地支的说法的.

经纬线都是假想 (imaginary)出来的线, 赤道是天然的纬线.经线从理论上来说, 任何连接南北两极的圆线都可以作为
prime meridian, 比如中国清朝的时候,还提出了自己的prime meridian. 因此, 需要从无数的子午线中 人为
地选出一条作为”首子午线”. 因为英国皇家天文台(Greenwich天文台)最先测量经线的长度, 所以把经过 Greenwich 天文台
子午仪中心的子午线作为经线的起点, 即0度子午线, 本初子午线.

Greenwich Village = the Village不是在英国, 而是在美国纽约.

GMT 又叫 UT0
经过 “地轴摆动”修正后的时间 叫 UT1, UT2
由铯原子钟提供的时间叫 “国际原子时” :TAI
那么, 把以上的所有时间: UT0, 1,2 TAI综合精确计算 提供的 “世界协调时” 就叫 UTC .
UTC与真的太阳时的误差在0.9秒内.否则, 要由巴黎…发布 “闰秒”.
UTC: universal time coordinated.

通常在程序中, php和javascript, jquery中, 就认为GMT和UTC是一样的, 没有区别的.

而CST, 则有 多义/歧义 解释了.
可以是 美国或澳大利亚的 Central Standard Time(中部标准时间)
也可以是 中国或古巴的标准时间: China/Cuba Standard Time
而在不同的语言中, 如php, java, 和 javascript中, 解释器/编译器对CST的理解不同, 而出错.

所以, 在编程中, 尽量少用 CST.

php和js/jquery中对时间/时区的操作?

  • 获得时间的函数:
php是 $dt = time()
js/jq 是 var dt = new Date();

// php中的time()时获得GMT时间戳的秒数. 是两个GMT时间的差 : 是指当前GMT英国Greenwich 0 时区的GMT时间
// 和unix纪元的 时间差.  跟php系统设置的 时区无关!
  • 也就是说, php的time()函数, 在某一时刻, 比如现在这一时刻, 在地球上的任何地方都是相同的. 因为他们都是返回的在伦敦的Greenwich的GMT时间.而不是本地时间, 所以跟php的系统设置时区无关.

  • 对日期/时间的操作
js获得new Date()对象后, 有丰富的成员函数来进行操作, 如getMonth, getDate, getDay, toString,UTC()等等
  • 对php的时间操作, 主要是date和gmdate的格式化问题
echo date("Y-m-d H:i:s"); 
// date() 返回的是: 当前(这一刻 time()函数执行/返回时) GMT标准时间 的"本地化时间" 的自定义格式时间
// date()跟php系统设置的时区有关!
echo gmdate("Y-m-d H:i:s");
// gmdate() 返回的是: 当前(这一刻 time()函数执行/返回时) GMT标准时间  的自定义格式时间
// gmdate() 跟你现在所处的位置无关, 跟php系统设置的时区无关!

也就说, date()和gmdate()的区别, 仅仅在于 处理的时间 是不同的!
  • strtotime(“str”)
strtotime("str"): 返回 string给定时间的 所对应的GMT标准时间的 unix时间戳,
如果当前php系统的设置的时区不是GMT标准时区,则在应用strtotime(string)时,系统会自动把时间
string折算成相应的GMT标准时间, 然后计算这个时间的unix时间戳。跟php系统设置的时区有关

关于时区

地球(地球和太阳在宇宙中的相对位置,和人类历史文化的原因)是自西向东自转,东边比西边先看到太阳,
东边的时间也比西边的早. 东边时刻与西边时刻的差值不仅要以时计,而且还要以分和秒来计算,
这给人们带来不便.

为了克服时间上的混乱, 1884年 在华盛顿召开的一次国际经度会议(又称国际子午线会议)上,
规定将全球划分为24个时区.它们是中时区(零时区)、东1-12区,西1-12区.
每个时区横跨经度15度,时间正好是1小时.最后的东、西第12区各跨经度7.5度,以东、西经180度为界.
每个时区的中央经线上的时间就是这个时区内统一采用的时间,称为区时.相邻两个时区的时间相差1小时.

例如,我国东8区的时间总比泰国东7区的时间快1小时,而比日本东9区的时间慢1小时.
因此,出国旅行的人,必须随时调整自己的手表,才能和当地时间相一致.
凡向西走,每过一个时区,就要把表向前拨1小时(比如2点拨到1点);凡向东走,每过一个时区,就要把表向后拨1小时
(比如1点拨到2点).

实际上,世界上不少国家和地区都不严格按时区来计算时间.为了在全国范围内采用统一的时间,
一般都把某一个时区的时间作为全国统一采用的时间.
例如,我国把首都北京所在的东8区的时间作为全国统一的时间,称为北京时间.
而实际上, 我国整个面积范围共跨了5个时区.
又例如,英国、法国、荷兰和比利时等国,虽地处中时区,但为了和欧洲大多数国家时间相一致,则采用东1区的时间.

如何设置php中的时区? 两种方法

  1. 如果可以修改服务器, 就在服务器中修改phh.ini文件:
[Date]
; Defines the default timezone used by the date functions
date.timezone = Asia/Shanghai 或者 Asia/Chongqing 或者 PRC
// 注意, 没有北京 Asia/Beijng
// 更注意的是, 如果phi.ini中没有[Date] date.timezone的话, 就要自己手动添加.
  1. 如果没有权限 不能 修改服务器上的php.ini, 就用函数方法
// 一般,最好在初始化 文件中 写
// 或调用时间函数之前, 写
ini_set('date.timezone', 'Asia/Shanghai 或者Asia/Chongqing 或者PRC');
ini_set('date.timezone', 'Etc/GMT-8'); // 后面是 -8 减8 , 这个Etc是linux中的/etc目录吗? 那最好不用?
date_default_timezone_set('Asia/Shanghai 或者Asia/Chongqing 或者PRC');
使用date_default_timezone_get()就可以获得系统 当前设置的 时区.

或者, 不用设置时区, 直接手动调整时间:
在显示/输出时间时, 都统一处理:
不使用date()
统一使用gmdate(), 但是在时间上加上 8*3600 这么多秒 到time()上去!
  1. php 手册上说的: date_default_timezone_set自 PHP 5.1.0 起(此版本日期时间函数被重写了),
string date_default_timezone_get ( void )
本函数返回  "默认时区" ,使用如下“假定”的顺序: 

■用 date_default_timezone_set() 函数设定的时区(如果设定了的话) 

■TZ 环境变量(如果非空) 

■date.timezone 配置选项(如果设定了的话) 

■自己推测(如果操作系统支持) 

■如果以上选择都不成功,则返回 UTC 
string date/gmdate ( string $format [, int $timestamp ] )
返回将整数 timestamp 按照给定的格式字串而产生的字符串。
如果没有给出时间戳则使用 "本地" 当前时间。换句话说,timestamp 是可选的,默认值为 time()。 

如果没有给出时间戳则使用 “本地” 当前时间。换句话说,timestamp 是可选的,默认值为 time()。

<?php
// date_default_timezone_set('Asia/Chongqing');
// ini_set('date.timezone', 'PRC');
// ini_set('date.timezone', 'prc');

$tz = date_default_timezone_get();
echo "默认时区是: $tz";

/* 好像没有设置TZ  (timezone) 这个常量 */
if(defined('TZ')) echo TZ; 
echo "<br />";

echo time();
echo "<br />";
echo gmdate('Y-m-d H:i:s');
echo "<br />";
echo date('Y-m-d H:i:s');

?>

那么time()函数的内部实现, 是不是 通过网络去访问 Greenwich的” 相关时间服务器” 而得到的呢? 好像不是, 因为即使是断了网, 还是能够获得time()函数的值? 应该是通过 操作系统 去实现的??

原文地址

https://www.cnblogs.com/bkylee/p/5260296.html

phpstorm 2017激活 2018/02/04日测试可用

1. 通过Licence Server 激活PHPStorm 2017.1:

  1. http://www.0-php.com:1017(可用,更新于20170621)2018/02/04测试可用

    http://idea.singee77.com/

    http://idea.lanyus.com/ (已被封杀)

    http://idea.qinxi1992.cn/ (测试时不可以)

2. 本地激活PHPStorm 2017.1(不上网):

  1. 加载文件LocalServer.zip
  2. 解压压缩文件,并选择与您的操作系统的名称的文件
  3. 我们给运行该文件的权限并运行该文件
  4. 选择一个许可证服务器,并在许可证服务器地址:指定地址 http://127.0.0.1:1017/
  5. 按下按钮OK

3. 直接用浏览器打开 http://idea.lanyus.com/

点击页面中的“获得注册码”,然后在注册时切换至Activation Code选项,输入获得的注册码一长串字符串,便可以注册成功了!(推荐用这种方式)

4. 若资金允许,请前往https://www.jetbrains.com/idea/buy/购买正版

endroid/qrcode php生成二维码

QR Code

By endroid

Latest Stable Version Build Status Total Downloads Monthly Downloads License Donate

This library helps you generate QR codes in a jiffy.

Installation

Use Composer to install the library.

$ composer require endroid/qrcode

Basic usage

use Endroid\QrCode\QrCode;

$qrCode = new QrCode('Life is too short to be generating QR codes');

header('Content-Type: '.$qrCode->getContentType());
echo $qrCode->writeString();

Advanced usage

use Endroid\QrCode\ErrorCorrectionLevel;
use Endroid\QrCode\LabelAlignment;
use Endroid\QrCode\QrCode;
use Symfony\Component\HttpFoundation\Response;

// Create a basic QR code
$qrCode = new QrCode('Life is too short to be generating QR codes');
$qrCode->setSize(300);

// Set advanced options
$qrCode->setWriterByName('png');
$qrCode->setMargin(10);
$qrCode->setEncoding('UTF-8');
$qrCode->setErrorCorrectionLevel(ErrorCorrectionLevel::HIGH);
$qrCode->setForegroundColor(['r' => 0, 'g' => 0, 'b' => 0]);
$qrCode->setBackgroundColor(['r' => 255, 'g' => 255, 'b' => 255]);
$qrCode->setLabel('Scan the code', 16, __DIR__.'/../assets/fonts/noto_sans.otf', LabelAlignment::CENTER);
$qrCode->setLogoPath(__DIR__.'/../assets/images/symfony.png');
$qrCode->setLogoWidth(150);
$qrCode->setValidateResult(false);

// Directly output the QR code
header('Content-Type: '.$qrCode->getContentType());
echo $qrCode->writeString();

// Save it to a file
$qrCode->writeFile(__DIR__.'/qrcode.png');

// Create a response object
$response = new Response($qrCode->writeString(), Response::HTTP_OK, ['Content-Type' => $qrCode->getContentType()]);

QR Code

Built-in validation reader

You can enable the built-in validation reader (disabled by default) by calling setValidateResult(true). This validation reader does not guarantee that the QR code will be readable by all readers but it helps you provide a minimum level of quality.

The readability of a QR code is primarily determined by the size, the input length, the error correction level and any possible logo over the image so you can tweak these parameters if you are looking for optimal results. Take note that the validator can consume quite amount of additional resources.

Symfony integration

The endroid/qrcode-bundle integrates the QR code library in Symfony for an even better experience.

  • Configure your defaults (like image size, default writer etc.)
  • Generate QR codes quickly from anywhere via the factory service
  • Generate QR codes directly by typing an URL like /qrcode/<text>.png?size=300
  • Generate QR codes or URLs directly from Twig using dedicated functions

Read the bundle documentation for more information.

Versioning

Version numbers follow the MAJOR.MINOR.PATCH scheme. Backwards compatibility breaking changes will be kept to a minimum but be aware that these can occur. Lock your dependencies for production and test your code when upgrading.

License

This bundle is under the MIT license. For the full copyright and license information please view the LICENSE file that was distributed with this source code.

Donation

If this project help you reduce time to develop, you can give me a cup of coffee 🙂

https://packagist.org/packages/endroid/qrcode

https://github.com/endroid/QrCode

 

<pre><?php
namespace app\controllers;
use Yii;
use yii\filters\AccessControl;
use yii\web\Controller;

use Endroid\QrCode\ErrorCorrectionLevel;
use Endroid\QrCode\LabelAlignment;
use Endroid\QrCode\QrCode;
use Symfony\Component\HttpFoundation\Response;
/**
 *
 */
class QrcodeController extends Controller
{


    public function actionIndex()
    {
        $rgbs=[
            '0'=>['r'=>'5','g'=>'152','b'=>'71'],//绿色
            '1'=>['r'=>'0','g'=>'100','b'=>'172'],//蓝色
            '2'=>['r'=>'78','g'=>'200','b'=>'149'],//青色
            '3'=>['r'=>'15','g'=>'162','b'=>'255'],//蓝色
            '4'=>['r'=>'249','g'=>'145','b'=>'10'],//黄色
            '5'=>['r'=>'90','g'=>'175','b'=>'156'],//青色
            '6'=>['r'=>'255','g'=>'107','b'=>'149'],//粉色
            '7'=>['r'=>'7','g'=>'170','b'=>'255'],//蓝色
            '8'=>['r'=>'0','g'=>'0','b'=>'0'],//黑色
            '9'=>['r'=>'18','g'=>'219','b'=>'226'],//水蓝色
        ];
        $random_keys=array_rand($rgbs,1);
        $rgb=$rgbs[$random_keys];
        $qrCode = new QrCode('http://m.biaobai.xin');
        $qrCode->setSize(300);
        // Set advanced options
        $qrCode->setWriterByName('png');
        $qrCode->setMargin(10);
        $qrCode->setEncoding('UTF-8');
        $qrCode->setErrorCorrectionLevel(ErrorCorrectionLevel::HIGH);
        $qrCode->setForegroundColor($rgb);
        $qrCode->setBackgroundColor(['r' => 255, 'g' => 255, 'b' => 255]);
//        $qrCode->setLabel('Scan the code', 16, __DIR__.'/../assets/fonts/noto_sans.otf', LabelAlignment::CENTER);
        $qrCode->setLogoPath(__DIR__.'/../logo.png');
        $qrCode->setLogoWidth(80);
        $qrCode->setValidateResult(false);

         // Directly output the QR code
        header('Content-Type: '.$qrCode->getContentType());
        echo $qrCode->writeString();

        // Save it to a file
        //$qrCode->writeFile(__DIR__.'/../qrcode.png');

        // Create a response object
        $response = new Response($qrCode->writeString(), Response::HTTP_OK, ['Content-Type' => $qrCode->getContentType()]);
    }

}


?></pre>

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

 

php中实现精确设置session过期时间的方法 保持登录状态

http://www.jb51.net/article/52309.htm

大多数据情况下我们对于session过期时间使用的是默认设置的时间,而对于一些有特殊要求的情况下我们可以设置一下session过期时间。

对此,可以在PHP中,设置php.ini,找到session.gc_maxlifetime = 1440 #(PHP5默认24分钟)
这里你可以随便设置一下过期时间.但是有人说设置以后,好象不起作用!
其实不是不起作用,而是因为系统默认:

1
2
session.gc_probability = 1
session.gc_divisor = 1000

garbage collection 有个概率的,1/1000就是session 1000次才有一次被回收。
只要你的访问量大了,那就能达到回收的效果.
或者你也可以设置一下session.gc_divisor 的值,
比如:session.gc_divisor = 1,这样就能明显的看到SESSION过期的效果了.

我们最常用的是在php程序中设置,如下例程序所示:

1
2
3
4
<?php
if(!isset($_SESSION['last_access'])||(time()-$_SESSION['last_access'])>60)
$_SESSION['last_access'] = time();
?>

这样就搞定了,如果要设置已过期的话也可以在程序中实现:

1
2
3
<?php
unset($_SESSION['last_access']);// 或 $_SESSION['last_access']='';
?>

session有过期的机制:

session.gc_maxlifetime 原来session 过期是一个小概率的事件,分别使用session.gc_probability和session.gc_divisor 来确定运行session 中gc 的概率 session.gc_probability和session.gc_divisor的默认值分别为 1和100。分别为分子和分母 所以session中gc的概率运行机会为1% 。如果修改这两个值,则会降低php的效率。所以这种方法是不对的!!
因此,修改php.ini文件中的gc_maxlifetime变量就可以延长session的过期时间了:(例如,我们把过期时间修改为86400秒)
session.gc_maxlifetime = 86400
然后,重启你的web服务(一般是apache)就可以了。

session“回收”何时发生:

默认情况下,每一次php请求,就会有1/100的概率发生回收,所以可能简单的理解为“每100次php请求就有一次回收发生”。这个概率是通过以下参数控制的
#概率是gc_probability/gc_divisor

1
2
session.gc_probability = 1
session.gc_divisor = 100

注意1:假设这种情况gc_maxlifetime=120,如果某个session文件最后修改时间是120秒之前,那么在下一次回收(1/100的概率)发生前,这个session仍然是有效的。

注意2:如果你的session使用session.save_path中使用别的地方保存session,session回收机制有可能不会自动处理过期session文件。这时需要定时手动(或者crontab)的删除过期的session:

1
cd /path/to/sessions; find -cmin +24 | xargs rm

PHP中的session永不过期

不修改程序是最好的方法了,因为如果修改程序,测试部一定非常郁闷,那么只能修改系统环境配置,其实很 简单,打开php.ini设置文件,修改三行如下:

1、session.use_cookies

把这个的值设置为1,利用cookie来传递sessionid

2、session.cookie_lifetime

这个代表SessionID在客户端Cookie储存的时间,默认是0,代表浏览器一关闭SessionID就作废……就是因为这个所以PHP的 session不能永久使用! 那么我们把它设置为一个我们认为很大的数字吧,999999999怎么样,可以的!就这样。

3、session.gc_maxlifetime

这个是Session数据在服务器端储存的时间,如果超过这个时间,那么Session数据就自动删除! 那么我们也把它设置为99999999。

就这样一切ok了,当然你不相信的话就测试一下看看——设置一个session值过个10天半个月的回来看看,如果你的电脑没有断电或者宕机,你仍然可以看见这个sessionid。

当然也可能你没有控制服务器的权限并不能像我一样幸运的可以修改php.ini设置,一切依靠我们自己也是有办法的,当然就必须利用到客户端存储 cookie了,把得到的sessionID存储到客户端的cookie里面,设置这个cookie的值,然后把这个值传递给session_id()这 个函数,具体做法如下:

1
2
3
4
5
6
7
8
9
<?php
session_start(); // 启动Session 
$_SESSION['count']; // 注册Session变量Count 
isset($PHPSESSID)?session_id($PHPSESSID):$PHPSESSID = session_id(); 
// 如果设置了$PHPSESSID,就将SessionID赋值为$PHPSESSID,否则生成SessionID 
$_SESSION['count']++; // 变量count加1 
setcookie('PHPSESSID', $PHPSESSID, time()+3156000); // 储存SessionID到Cookie中 
echo $count; // 显示Session变量count的值 
?>

session失效不传递

我们先写个php文件:<?=phpinfo()?>, 传到服务器去看看服务器的参数配置。
转到session部分,看到session.use_trans_sid参数被设为了零。
这个参数指定了是否启用透明SID支持,即session是否随着URL传递。我个人的理解是,一旦这个参数被设为0,那么每个URL都会启一个session。这样后面页面就无法追踪得到前面一个页面的session,也就是我们所说的无法传递。两个页面在服务器端生成了两个session文件,且无关联。(此处精确原理有待确认)
所以一个办法是在配置文件php.ini里把session.use_trans_sid的值改成1。

当然我们知道,不是谁都有权限去改php的配置的,那么还有什么间接的解决办法呢?
下面就用两个实例来说明:
文件1 test1.php

1
2
3
4
5
6
7
8
9
10
<?php
//表明是使用用户ID为标识的session
session_id(SID);
//启动session
session_start();
//将session的name赋值为Havi
$_SESSION['name']="Havi";
//输出session,并设置超链接到第二页test2.php
echo "<a href="test2.php" rel="external nofollow" >".$_SESSION['name']."</a>";
?>

文件2: test2.php

1
2
3
4
5
6
7
8
<?php
表明是使用用户ID为标识的session
session_id(SID);
//启动session
session_start();
//输出test1.php中传递的session。
echo "This is ".$_SESSION['name'];
?>

所以,重点是在session_start();前加上session_id(SID);,这样页面转换时,服务器使用的是用户保存在服务器session文件夹里的session,解决了传递的问题。
不过有朋友会反映说,这样一来,多个用户的session写在一个SID里了,那Session的价值就发挥不出来了。所以还有一招来解决此问题,不用加session_id(SID);前提是你对服务器的php.ini有配置的权限:
output_buffering改成ON,道理就不表了。
第二个可能的原因是对服务器保存session的文件夹没有读取的权限,还是回到phpinfo.php中,查看session保存的地址:

1
session.save_path: var/tmp

所以就是检查下var/tmp文件夹是否可写。
写一个文件:test3.php来测试一下:

1
2
3
<?php
echo var_dump(is_writeable(ini_get("session.save_path")));
?>

如果返回bool(false),证明文件夹写权限被限制了,那就换个文件夹咯,在你编写的网页里加入:

1
2
3
4
5
6
7
//设置当前目录下session子文件夹为session保存路径。
$sessSavePath = dirname(__FILE__).'/session/';
//如果新路径可读可写(可通过FTP上变更文件夹属性为777实现),则让该路径生效。
if(is_writeable($sessSavePath) && is_readable($sessSavePath))
{
session_save_path($sessSavePath);
}

register_shutdown_function 函数详解

php开发测试及线上的时候可以根据不同情况设定错误和异常处理需要用到有

设定错误和异常处理三函数

  1. register_shutdown_function(array(‘Debug’,‘fatalError’)); //定义PHP程序执行完成后执行的函数
  2. set_error_handler(array(‘Debug’,’appError’)); // 设置一个用户定义的错误处理函数
  3. set_exception_handler(array(‘Debug’,‘appException’)); //自定义异常处理。

下面讲一下register_shutdown_function() 函数.

功能:register_shutdown_function() 函数可实现当程序执行完成后执行的函数,其功能为可实现程序执行完成的后续操作。程序在运行的时候可能存在执行超时,或强制关闭等情况,但这种情况下默认的提示是非常不友好的,如果使用register_shutdown_function()函数捕获异常,就能提供更加友好的错误展示方式,同时可以实现一些功能的后续操作,如执行完成后的临时数据清理,包括临时文件等。

可以这样理解调用条件:

1、当页面被用户强制停止时

2、当程序代码运行超时时

3、当PHP代码执行完成时,代码执行存在异常和错误、警告

实例说明

1. 一个简介的例子 , 调用一个函数

  1. <?php
  2. function test() {
  3.     echo “test()”;
  4. }
  5. register_shutdown_function(array(“test”));
  6. echo “show: “;
  7. ?>

这个例子输出

  1.  show: test()    

这个函数的作用就是在退出脚本前,调用已经注册的函数,并执行该函数。

2. 在类中用一个数组作为一个参数

  1. <?php
  2.     class ClassDemo {
  3.         public function __construct() {
  4.             register_shutdown_function(array($this, “f”));
  5.         }
  6.  
  7.         public function f() {
  8.             echo “f()”;
  9.         }
  10.     }
  11.  
  12.     $demo = new ClassDemo();
  13.     echo “before </br>”;
  14. ?>

输出:

  1. before
  2. f()

3. 带有参数的例子:

  1. <?php
  2. function f($str) {
  3.         echo $str.“<br>”;
  4. }
  5.  
  6. register_shutdown_function(“f”,“hello”);
  7.     class ClassDemo {
  8.         public function __construct() {
  9.             register_shutdown_function(array($this, “f”),“hello”);
  10.         }
  11.  
  12.         public function f($str) {
  13.             echo “f():”.$str;
  14.         }
  15.     }
  16.  
  17.    $demo = new ClassDemo();
  18.    echo “before </br>”;  
  19. ?>

注意事项

1,register_shutdown_function()函数可重复调用,但执行的顺序与注册的顺序相同
2,如果在调用register_shutdown_function()函数之前有exit()函数调用,register_shutdown_function()函数将不能执行
3,PHP4后支持注册函数参数传递
4,在某些服务端,如Apache,当前目录在register_shutdown_function()函数中能够改变
5,register_shutdown_function()函数执行在headers发送之后
总而言之 出现500错误(不友好错误)。把这段代码放在文件前面。执行,即可看到错误信息。

register_shutdown_function(function(){ var_dump(error_get_last()); });

PHP微服务框架即Micro Service Framework For PHP

Micro Service Framework For PHP

PHP微服务框架即“Micro Service Framework For PHP”,是Camera360社区服务器端团队基于Swoole自主研发现代化的PHP协程服务框架,简称msf或者php-msf,是Swoole的工程级企业应用框架,经受了Camera360亿级用户高并发大流量的考验。php-msf由Camera360服务器团队主导研发,会持续更新与维护,也希望有更多优秀的Swoole应用实践开发者加入。php-msf核心设计思想是采用协程、异步、并行的创新技术手段提高系统的单机吞吐能力,降低整体服务器成本。

主要特性

  • 精简版的MVC框架
  • IO密集性业务的单机处理能力提升5-10倍
  • 代码常驻内存
  • 支持对象池
  • 支持Redis连接池、MySQL连接池
  • 支持Redis分布式、master-slave部署结构的集群
  • 支持异步、并行
  • 基于PHP Yield实现协程
  • 内建http/redis/mysql/mongodb/task等协程客户端
  • 纯异步的Http Server
  • RPC Server/Client
  • 支持命令行模式
  • 支持独立进程的定时器
  • 支持独立配置进程

环境要求

  • Linux,FreeBSD,MacOS(有兼容问题)
  • Linux内核版本2.3.32以上(支持epoll)
  • PHP-7.0及以上版本(生产环境建议使用PHP-7.1)
  • gcc-4.4以上版本
  • swoole-1.9.15及以上版本(暂不支持Swoole-2.0)
  • hiredis-0.13.3
  • yac
  • phpredis
  • composer

文档

框架手册(Gitbook): PHP-MSF开发手册

API Document(Rawgit): 类文档

示例DEMO项目: PHP-MSF DEMO

帮助完善文档: https://github.com/pinguo/php-msf-docs,请提交PR。

交流与反馈

PHP-MSF#1群(QQ): 614054288

快速起步

$>php -r "copy('https://raw.githubusercontent.com/pinguo/php-msf-docker/master/installer.php', 'installer.php');include('installer.php');" && source ~/.bashrc

installer.php会检查运行环境,根据你的自定义配置,自动创建项目模板,composer安装依赖,启动服务。如果cdn.rawgit.com无法访问,可以直接克隆或者下载php-msf-docker,提取installer.php,然后直接运行php installer.php

如果一切顺利,运行到最后你将看到如下的输出:

[2017-09-06 16:08:34] Run composer install success
[2017-09-06 16:08:34] Congratulations, all are installed successfully!
[2017-09-06 16:08:34] You can, visit http://127.0.0.1:8990/Welcome for test
      _______                               ____
________  / /_  ____        ____ ___  _____/ __/
___/ __ \/ __ \/ __ \______/ __ `__ \/ ___/ /_
__/ /_/ / / / / /_/ /_____/ / / / / (__  ) __/
_/ .___/_/ /_/ .___/     /_/ /_/ /_/____/_/
/_/         /_/         Camera360 Open Source TM
[2017-09-06 16:08:34] Swoole  Version: 1.9.18
[2017-09-06 16:08:34] PHP     Version: 7.1.8
[2017-09-06 16:08:34] Application ENV: docker
[2017-09-06 16:08:34] Listen     Addr: 0.0.0.0
[2017-09-06 16:08:34] Listen     Port: 8990

访问测试:

$>curl http://127.0.0.1:8990/Welcome
hello world!

注意端口,如果你不是8990,你需要修改,然后访问测试。

标准应用结构

├── app // PHP业务代码
│   ├── AppServer.php // 应用server类,可根据需求自定义
│   ├── Controllers // 控制器类目录
│   ├── Lib // 特殊逻辑处理类目录
│   ├── Models // Model类目录
│   ├── Route // 特殊路由规则类目录
│   ├── Tasks // Task类目录
│   └── Views // 视图文件目录
├── build.sh // 构建脚本(拉取docker镜像,启动容器)
├── checkstyle.sh // 代码检查脚本
├── composer.json // composer包依赖配置文件
├── config // 配置目录
├── server.php // server启动脚本
├── console.php // 命令行脚本
├── test // 单元测试目录

上述为基于php-msf的标准应用结构,一键安装程序installer.php会自动生成目录,用户可以根据需求创建一些自定义目录,只要符合psr4标准即可自动加载。

服务启动

调试模式

$>./server.php start

Daemon模式

$>./server.php start -d

停止服务

$>./server.php stop

重启服务

$>./server.php restart

Docker

我们制作了Docker镜像,方便Docker用户快速的安装环境,运行PHP-MSF DEMO工程。另外期望在开发环境修改代码实时预览效果,建议使用Docker for Mac/Windows桌面版。

如果是升级Docker,它会自动迁移原有的镜像和容器,请耐心等待,千万不能中途kill掉Docker进程,否则再想迁移就难了。

Docker Registry(阿里云):

  • 公网地址: docker pull registry.cn-hangzhou.aliyuncs.com/pinguo-ops/php-msf-docker:latest
  • 经典内网: docker pull registry-internal.cn-hangzhou.aliyuncs.com/pinguo-ops/php-msf-docker:latest
  • VPC网络: docker pull registry-vpc.cn-hangzhou.aliyuncs.com/pinguo-ops/php-msf-docker:latest
  • DockerHub(国外): docker pull pinguoops/php-msf-docker

框架定位

我们专注打造稳定高性能纯异步基于HTTP的微服务框架,作为nginx+php-fpm的替代技术栈实现架构的微服务化;而Tcp/WebSocket Server将作为插件的形势支持,或者作为其他独立的开源项目。

对于小型团队或者业务系统我们建议还是采用传统的nginx+php-fpm技术栈,对于成本和性能来说没有瓶颈,也就完全没有必要引入全新的技术栈。

对于大中型团队或者业务系统,处在服务治理或者服务化演进的重要阶段,php-msf是可选方案之一。

对于庞大的PHP应用集群,想要大幅节约服务器成本,提升服务性能,php-msf是可选方案之一。

对于聚合服务,比如大型的网站首页,想要通过服务器端聚合内容整合数据,php-msf是可选方案之一。

手工安装

推荐安装方式,通过编辑项目composer.json加入依赖pinguo/php-msf

{
    "require": {
        "pinguo/php-msf": ">=3.0.0"
    },
    "minimum-stability": "dev"
}

"minimum-stability": "dev"这个配置选项必须加上,因为日志组件依赖"monolog/monolog": "2.0.x-dev",并且monolog/monolog无2.0的release包,不过我们在生产环境已经验证其稳定性。

项目原则

稳定

php-msf经受了Camera360社区服务大流量、高并发的洗礼,稳定性得到充分验证。稳定性是我们花了大量时间、精力去解决的最重要问题,是三大原则的最重要原则。

高性能

IO密集性业务的单机处理能力提升5-10倍,这是生产环境中得出的真实数据,如Camera360社区某聚合服务在流量高峰需要40台服务器抗住流量,而采用php-msf重构之后只需要4台相同配置的服务器就可以抗住所有流量。

简单

由于Swoole复杂的进程模型,并且有同步阻塞和异步非阻塞之分,所以在运行相同代码逻辑时,可能在调用方式、传递参数都不一致,从而直线拉高了学习成本,我们为了屏蔽低层的差异,做了大量的工作,实现和传统MVC框架的唯一区别在于添加“yield”关键字。我们参考了Yii2框架的部分代码实践,我们期望无缝的从Yii2开发切换过来。

上述三大原则,是我们在新增特性、功能实现时,投票或者合并代码的依据,任何影响这些原则的PR也将会被拒绝。

关于协程

目前社区有几个PHP开源项目支持协程,它们大多采用Generator+Yield来实现,但是实现的细微差别会导致性能相差甚远,我们应该认识到协程能够以同步的代码书写方式而运行异步逻辑,故协程调度器的性能一定要足够的高,php-msf的协程调度性能是原生异步回调方式的80%,也就是说某个API采用原生异步回调写法QPS为10000,通过php-msf协程调度器调度QPS为8000。

为什么是微服务框架?

目前php-msf还在起步阶段,我们花了大量的时间和精力解决稳定性、高性能、内存问题,因为我们认为“基石”是“万丈高楼”的最基本的保障,只有基础打得牢,才能将“大楼”建设得“更高”。3.0版本是我们开源的起始版本,是我们迈出的重要一步,接下来我们重点会是分布式微服务框架的打磨。

另外,由于基于PHP常驻进程,并直接解析HTTP或者TCP请求,这是服务化最重要的支撑,基于此我们可以做很多原来不敢去实现的想法,总之想像空间很大。

感谢

php-msf最开始基于SwooleDistributed-1.7.x开发,而此次开源版本中,连接池主要采用了SD的实现。由于我们框架定位、解决的业务场景、稳定性的要求、代码风格等差异太大,因此我们决定自主研发微服务框架,每个框架都有自己的特色和优点,选择合适自己公司和业务场景的框架最重要,同时在此也感谢白猫;另外,在研发php-msf框架及生产环境应用过程中,遇到很多底层问题,不过都一一解决,而这些问题能够解决最重要就是Swoole开源项目创始人韩天峰-Rango的大力支持,在此深表感谢。

License

GNU General Public License, version 2 see https://www.gnu.org/licenses/gpl-2.0.html