版本特性

0311lc.com说:

 

 

======php.8.2=============

PHP8.2 解决了 PHP 类型系统的几个缺点和限制,允许 PHP 应用采用更好的类型安全。包括添加了 true 类型,允许 null 和 false 作为独立的类型使用,并支持 DNF 类型(泛型解析)。

PHP8.2 支持分离范式类型,现在可以进行组合联合类型和交际类型,这可以定义声明精确而富有表现力的参数、返回值和属性。

php8.2 之前

class Foo {  public function bar(mixed $entity) {        if ((($entity instanceof A) && ($entity instanceof B)) || ($entity === null)) {            return $entity;        }        throw new Exception('Invalid entity');    }}
现在

class Foo {  public function bar((A&B)|null $entity) {        return $entity;    }}
支持 true 和 false 作为独立的类型,如果 bool 始终相同的时候可以用它来声明。

function alwaysReturnsFalse(): false {}function alwaysReturnsNull(): null {}function alwaysReturnsTrue(): true {}
其中 null 的类型在之前的版本中就可以在联合类型声明中使用,现在可以独立使用了。

只读类
PHP8.1 增加了一个 readonly 的属性声明。一个 readonly 的属性只能设置一次,并且 PHP 会阻止任何作用域内的修改。

PHP8.2 对 readonly 声明进行更进一步的使用,可以将类声明为 readonly。当一个类被声明为 readonly,它的所有属性都会自动声明 readonly。此外,这个类不能使用动态属性,以确保所有的属性都是有定义的。

readonly class User {    public string $username;    public string $uid;}
所有的属性都会自动声明城 readonly。

新的随机数扩展
在 PHP 的历史发展中,它支持各种各样的随机数生成器,他们有不同程度的性能和不同的用例,并且适合安全应用程序。PHP8.2 更进一步,将所有与随机数相关的功能重构为一个名为 random 的扩展。新的扩展不会破坏任何现有的接口使用,因此现有的 rand,mt_rand 函数将继续工作,不需要任何更改。它还提供了一个对象接口,用可插拔的体系生成随机数,因此很容易模拟随机数生成器并提供新的随机数生成器,从而市 PHP 应用程序安全且易于测试。

trait 常量
在 PHP8.2 中,可以在 trait 中声明常量。trait 不能直接访问,但当类使用 trait 时,这些常量就变成了类的常量。

trait Foo{  public const CONSTANT = 1;}class Bar{    use Foo;}var_dump(Bar::CONSTANT); // 1var_dump(Foo::CONSTANT); // Error
敏感参数支持
PHP8.2 新增了一个内置参数属性命名:#[\SensitiveParameter]。能够使 PHP 在堆栈跟踪和错误消息中隐藏掉实际值。

我们经常会在参数或属性中定义密码、秘钥或其他敏感信息。当 PHP 发生错误时,这些值会被记录下来。显示到屏幕上或者记录到日志中。这样人们就能通过这些方式得到敏感数据。

比如下面的例子:

function passwordHash(#[\SensitiveParameter] string $password)  {       debug_print_backtrace(); } passwordHash('hunter2');
打印的内容如下:

array(1) {[0]=> array(4) {  ["file"]=> string(38) "..."["line"]=> int(9)["function"]=> string(3) "foo"  ["args"]=> array(1) {     // [0]=> string(38) "hunter2" 这一行不会被打印出来   [0]=> object(SensitiveParameterValue)#1 (0) {}} }}
hunter2 不会被打印出来。

新的函数和类
解析 INI 数量值:ini_parse_quantity

将 PHP ini 值识别成字节。

ini_parse_quantity('256M'); // 268435456
curl 维持活动:curl_upkeep

在 PHP8.2 中,curl 扩展会触发底层 curl 库来运行必要任务,以保持 curl 连接存活。最常见的用法就是定期调用 curl_upkeep 来实现 http 持久连接(keep-alive)。

检索密码长度:openssl_cipher_key_length

在 PHP8.2 OpenSSL 中,有一个名为 openssl_cipher_key_length 的函数,能够接受任何支持的密码所需的秘钥长度,在之前需要硬编码才能实现:

openssl_cipher_key_length("CHACHA20-POLY1305"); // 32openssl_cipher_key_length("AES-128-GCM"); // 16openssl_cipher_key_length("AES-256-GCM"); // 32
重置记录的峰值内存使用量:memory_reset_peak_usage

这对于多次调用或迭代调用时很有用。

PHP8.2 中的弃用
PHP8.2 也带来了相当一部分的弃用。当语法、函数和特性被弃用时,PHP 会发起一个弃用通知,该通知不应该中断 PHP 程序,但会被记录到错误日志中。

注意:PHP8.0 以后,PHP 的默认错误报告行为是 E_ALL
已弃用动态属性
PHP8.2 中最值得注意的弃用之一就是弃用动态属性。如果一个类属性没有声明就被调用或赋值,就会退出程序。

class User {  public int $uid;}$user = new User();$user->name = 'Foo';
这个可能会影响到很多的的 PHP 遗留程序,推荐的修复方法是在类型中声明属性。

对此也有例外用法,比如 stdClass 和它的子类将正常使用,__get 和__set 魔术方法将正常使用,或者声明 #AllowDynamicProperties。

===========php8.1=========

=======================Php8.1============
让我们首先介绍PHP 8.1中的所有新特性。这是一个相当多的清单。

注意:随着PHP 8.1发布日期的临近,此列表可能会增加或缩小。我们将致力于使其保持最新状态。

纯交集类型
枚举
永不返回类型
Fibers
新的只读属性
定义最终类常量
新的fsync()和fdatasync()函数
新的array_is_list()函数
新的Sodium XChaCha20函数
新的IntlDatePatternGenerator类
支持AVIF图像格式
新的$_FILES:目录上传的full_path键
对字符串键控数组的数组解包支持
显式八进制数字表示法
MurmurHash3和xxHash哈希算法支持
DNS-over-HTTPS (DoH) 支持
使用CURLStringFile从字符串上传文件
新的MYSQLI_REFRESH_REPLICA常量
使用继承缓存提高性能
一流的可调用语法
纯交集类型
PHP 8.1添加了对交集类型的支持。它类似于PHP 8.0 中引入的联合类型,但它们的预期用途恰恰相反。

为了更好地理解它的用法,让我们回顾一下PHP中类型声明的工作原理。

本质上,您可以向函数参数、返回值和类属性添加类型声明。这种分配称为类型提示,并确保值在调用时是正确的类型。否则,它会立即抛出一个TypeError。反过来,这可以帮助您更好地调试代码。

但是,声明单一类型有其局限性。联合类型通过允许您声明具有多种类型的值来帮助您克服这个问题,并且输入必须至少满足声明的类型之一。

另一方面,RFC将交集类型描述为:

“交集类型”需要一个值来满足多个类型约束而不是单个约束。

…纯交集类型使用语法 T1&T2&… 指定,可用于当前接受类型的所有位置…

请注意使用&(AND) 运算符来声明交集类型。相反,我们使用|(OR) 运算符来声明联合类型。

在交集类型中使用大多数标准类型将导致永远无法满足的类型(例如整数和字符串)。因此,交集类型只能包括类类型(即接口和类名)。

以下是如何使用交集类型的示例代码:

复制
class A {
private Traversable&Countable $countableIterator;
public function setIterator(Traversable&Countable $countableIterator): void {
$this->countableIterator = $countableIterator;
}
public function getIterator(): Traversable&Countable {
return $this->countableIterator;
}
}
在上面的代码中,我们将变量countableIterator定义为两种类型的交集:Traversable和Countable。在这种情况下,声明的两种类型是接口。

交集类型也符合已用于类型检查和继承的标准PHP变化规则。但是还有两个关于交集类型如何与子类型交互的额外规则。您可以在其 RFC 中阅读有关交集类型差异规则的更多信息。

在某些编程语言中,您可以在同一个声明中组合联合类型和交集类型。但是PHP 8.1禁止它。因此,它的实现被称为“纯”交集类型。但是,RFC 确实提到它“留作未来范围”。

枚举
PHP 8.1终于添加了对枚举(也称为枚举或枚举类型)的支持。它们是用户定义的数据类型,由一组可能的值组成。

编程语言中最常见的枚举示例是布尔类型,具有true和false两个可能的值。它是如此普遍,以至于它融入了许多现代编程语言。

根据RFC,PHP 中的枚举首先将被限制为“单元枚举”:

此RFC的范围仅限于“单元枚举”,即枚举本身就是一个值,而不是简单的原始常量的花哨语法,并且不包括附加的相关信息。此功能极大地扩展了对数据建模、自定义类型定义和 monad 样式行为的支持。枚举启用了“使无效状态不可表示”的建模技术,这会导致更健壮的代码,而无需进行详尽的测试。

为了达到这个阶段,PHP团队研究了许多已经支持枚举的语言。他们的调查发现,您可以将枚举分为三类:花式常量、花式对象和完整代数数据类型 (ADT)。这是一个有趣的阅读!

PHP 实现了“Fancy Objects”枚举,并计划在未来将其扩展到完整的ADT。它在概念和语义上都模仿了Swift、Rust和Kotlin中的枚举类型,尽管它没有直接模仿它们中的任何一个。

RFC使用一副牌中著名的西装类比来解释它是如何工作的:

复制
enum Suit {
case Hearts;
case Diamonds;
case Clubs;
case Spades;
}
在这里,Suit枚举定义了四个可能的值:Hearts、Diamonds、Clubs和Spades。您可以直接访问使用语法这些值:Suit::Hearts,Suit::Diamonds,Suit::Clubs,和Suit::Spades。

这种用法可能看起来很熟悉,因为枚举是建立在类和对象之上的。它们的行为相似并且具有几乎完全相同的要求。枚举与类、接口和特征共享相同的命名空间。

上面提到的枚举称为Pure Enums。

如果您想为任何情况提供标量等效值,您还可以定义支持枚举。但是,支持的枚举只能有一种类型,int或者string(永远不会)。

复制
enum Suit: string {
case Hearts = 'H';
case Diamonds = 'D';
case Clubs = 'C';
case Spades = 'S';
}
此外,支持枚举的所有不同情况都必须具有唯一值。你永远不能混合纯枚举和支持枚举。

RFC进一步深入探讨了枚举方法、静态方法、常量、常量表达式等等。涵盖所有这些超出了本文的范围。您可以参考文档以熟悉它的所有优点。

never 返回类型
PHP 8.1添加了一个名为never. 在 alwaysthrow或exit.

根据它的RFC,URL重定向函数总是exit(显式或隐式)是其使用的一个很好的例子:

复制
function redirect(string $uri): never {
header('Location: ' . $uri);
exit();
}
function redirectToLoginPage(): never {
redirect('/login');
}
一个never-declared函数应满足三个条件:

它不应该有return明确定义的语句。
它不应该有return隐式定义的语句(例如if-else语句)。
它必须以exit语句(显式或隐式)结束其执行。
上面的URL重定向示例显示了never返回类型的显式和隐式用法。

在never返回类型共享与许多相似之处void返回类型。它们都确保函数或方法不返回值。但是,它的不同之处在于执行更严格的规则。例如,void-declared 函数仍然可以return没有显式值,但您不能对never-declared 函数执行相同的操作。

根据经验,void当您希望 PHP 在函数调用后继续执行时,请继续执行。never当你想要相反的时候就去吧。

此外,never定义为“bottom”类型。因此,任何声明的类方法never都“never”不能将其返回类型更改为其他类型。但是,您可以使用void-declared 方法扩展never-declared 方法。

info: 原始RFC将never返回类型列为noreturn,这是两个PHP静态分析工具(即Psalm和PHPStan)已经支持的返回类型。由于这是由Psalm和PHPStan的作者自己提出的,因此他们保留了其术语。但是,由于命名约定,PHP团队对noreturn vs never进行了民意调查,never最终成为永远的赢家。因此,对于PHP 8.1+版本,始终使用never代替noreturn.

Fibers
从历史上看,PHP代码几乎一直是同步代码。代码执行暂停,直到返回结果,即使是 I/O 操作。您可以想象为什么这个过程可能会使代码执行速度变慢。

有多种第三方解决方案可以克服这一障碍,允许开发人员异步编写PHP代码,尤其是并发 I/O 操作。一些流行的示例包括amphp、ReactPHP和Guzzle。

但是,在PHP中没有处理此类实例的标准方法。此外,在同一个调用堆栈中处理同步和异步代码会导致其他问题。

Fibers是PHP通过虚拟线程(或绿色线程)处理并行性的方式。它试图通过允许 PHP 函数中断而不影响整个调用堆栈来消除同步和异步代码之间的差异。

以下是RFC的承诺:

向PHP添加对Fibers的支持。
引入一个新的Fiber类和对应的反射类ReflectionFiber。
添加异常类FiberError和FiberExit来表示错误。
Fibers允许现有接口(PSR-7、Doctrine ORM等)的透明非阻塞I/O实现。那是因为占位符(promise)对象被消除了。相反,函数可以声明I/O结果类型,而不是无法指定解析类型的占位符对象,因为PHP不支持泛型。
您可以使用Fibers开发全栈、可中断的PHP函数,然后您可以使用这些函数在PHP中实现协作多任务处理。当Fiber暂停整个执行堆栈时,您可以放心,因为它不会损害您的其余代码。

图表说明了使用Fibers的PHP代码执行流程。

为了说明Fibers的用法,它的RFC使用了这个简单的例子:

复制
$fiber = new Fiber(function (): void {
$value = Fiber::suspend('fiber');
echo "Value used to resume fiber: ", $value, "\n";
});
$value = $fiber->start();
echo "Value from fiber suspending: ", $value, "\n";
$fiber->resume('test');
你在上面的代码中创建了一个“fiber”,并立即用字符串挂起它fiber。该echo声明用作fiber恢复的视觉提示。

您可以通过调用$fiber->start()检索此字符串值。

然后,使用字符串“test”恢复fiber,该字符串是对Fiber::suspend()的调用返回的。完整代码执行会产生如下输出:

复制
Value from fiber suspending: fiber
Value used to resume fiber: test
这是PHP Fibers工作的准系统教科书示例。这是执行七个异步GET请求的另一个Fibers示例。

尽管如此,大多数PHP开发人员永远不会直接处理Fibers。RFC甚至提出了同样的建议:

Fibers是大多数用户不会直接使用的高级功能。此功能主要针对库和框架作者,以提供事件循环和异步编程 API。Fibers允许在任何时候将异步代码执行无缝集成到同步代码中,而无需修改应用程序调用堆栈或添加样板代码。

Fiber API不应直接在应用程序级代码中使用。Fibers提供了一个基本的、低级别的流控制API来创建更高级别的抽象,然后在应用程序代码中使用这些抽象。

考虑到它的性能优势,您可以期待PHP库和框架能够利用这一新特性。看看他们如何在他们的生态系统中实施Fibers会很有趣。

新的readonly属性
PHP 8.1添加了对readonly属性的支持。它们只能从它们被声明的作用域初始化一次。初始化后,您永远无法修改它们的值。这样做会引发错误异常。

RFC写道:

一个只读属性只能使用一次,并且只能从已申报范围的初始化。对该属性的任何其他分配或修改都将导致Error异常。

这是一个如何使用它的示例:

复制
class Test {
public readonly string $kinsta;
public function __construct(string $kinsta) {
// Legal initialization.
$this->kinsta = $kinsta;
}
}
一旦初始化,就再也回不去了。将此功能融入PHP会大大减少通常用于启用此函数的样板代码。

readonly属性在类内部和外部都提供了强大的不变性保证。中间运行什么代码并不重要。调用readonly属性将始终返回相同的值。

但是,readonly在特定用例中使用该属性可能并不理想。例如,您只能将它们与类型化属性一起使用,因为没有类型的声明是隐式的null,不能是readonly。

此外,设置readonly属性不会使对象不可变。该readonly属性将保存相同的对象,但该对象本身可以更改。

此属性的另一个小问题是您无法克隆它。已经有针对此特定用例的解决方法。如有必要,请查看它。

定义final类常量
从PHP 8.0开始,您可以使用其子类覆盖类常量。这是由于在PHP中实现继承的方式。

以下是如何覆盖先前声明的常量值的示例:

复制
class Moo
{
public const M = "moo";
}
class Meow extends Moo
{
public const M = "meow";
}
现在,如果奶牛想要更严格地控​​制猫的行为(至少在常量方面),他们可以使用PHP 8.1的新final修饰符来实现。

一旦你声明了一个常量为 final,就意味着。

复制
class Moo
{
final public const M = "moo";
}
class Meow extends Moo
{
public const M = "meow";
}
// Fatal error: Meow::M cannot override final constant Moo::M
您可以在最后的类常量PHP RFC中阅读更多关于它的内容。

新的fsync()和fdatasync()函数
PHP 8.1添加了两个名为fsync()和fdatasync()新文件系统函数。对于那些习惯于Linux同名函数的人来说,它们似乎很熟悉。那是因为它们是相关的,只是为PHP实现的。

事实上,这一补充早该进行了。PHP是少数仍未实现fsync() 和 fdatasync() 的主要编程语言之一——也就是说,直到PHP 8.1。

fsync()函数类似于PHP现有的fflush()函数,但在一个方面有很大不同。而fflush()将应用程序的内部缓冲区刷新到操作系统,fsync()则更进一步并确保将内部缓冲区刷新到物理存储。这确保了完整且持久的写入,以便您即使在应用程序或系统崩溃后也可以检索数据。

这是一个如何使用它的示例。

复制
$doc = 'kinsta.txt';
$kin = fopen($doc, 'ki');
fwrite($kin, 'doc info');
fwrite($kin, "\r\n");
fwrite($kin, 'more info');
fsync($kin);
fclose($kin);
fsync()在末尾添加调用可确保保存在 PHP 或操作系统内部缓冲区中的任何数据都被写入存储。在此之前,所有其他代码执行都将被阻止。

它的相关函数是fdatasync()。使用它来同步数据,但不一定是元数据。对于元数据不是必需的数据,此函数调用会使写入过程更快一点。

但是,您应该注意PHP 8.1在Windows下尚不完全支持fdatasync()。它只是作为fsync()的别名。在POSIX上,fdatasync()已正确实施。

新的array_is_list()函数
PHP数组可以保存整数和字符串键。这意味着您可以将它们用于多种用途,包括列表、哈希表、字典、集合、堆栈、队列等等。您甚至可以在数组中包含数组,从而创建多维数组。

您可以有效地检查特定条目是否为数组,但检查它是否有任何缺失的数组偏移量、乱序键等就不是那么容易了。简而言之,您无法快速验证数组是否为列表。

所述array_is_list()函数检查是否一个数组的键是按顺序从0开始,并与没有间隙。如果满足所有条件,它将返回true。默认情况下,它还返回true空数组。

以下是在同时满足true和false条件的情况下使用它的几个示例:

复制
// true array_is_list() examples
array_is_list([]); // true
array_is_list([1, 2, 3]); // true
array_is_list(['cats', 2, 3]); // true
array_is_list(['cats', 'dogs']); // true
array_is_list([0 => 'cats', 'dogs']); // true
array_is_list([0 => 'cats', 1 => 'dogs']); // true
// false array_is_list() examples
array_is_list([1 => 'cats', 'dogs']); // as first key isn't 0
array_is_list([1 => 'cats', 0 => 'dogs']); // keys are out of order
array_is_list([0 => 'cats', 'bark' => 'dogs']); // non-integer keys
array_is_list([0 => 'cats', 2 => 'dogs']); // gap in between keys
带有乱序键的PHP数组列表是潜在的错误来源。在继续执行代码之前,使用此函数强制严格遵守列表要求是对PHP的一个很好的补充。

新的Sodium XChaCha20函数
Sodium是一个现代的、易于使用的加密库,用于加密、解密、密码散列、签名等。该PECL libsodium包增加了对钠的包装,使PHP开发人员可以使用它。

即使是Facebook、Discord、Malwarebytes和Valve等领先的科技公司也使用libsodium来通过快速安全的连接来保护他们的用户。

libsodium支持XChaCha20加密算法对数据进行加密和解密,特别是对流加密。同样,PECL libsodium扩展已经支持XChaCha20,但仅支持Poly1305消息验证代码。

许多PHP应用程序直接使用XChaCha20进行流加密。为了让事情变得更简单,从PHP 8.1开始,您将拥有三个新函数,无需身份验证即可使用XChaCha20加密或解密数据。这种模式称为“分离模式”。

新推出的XChaCha20函数是:

sodium_crypto_stream_xchacha20_keygen: 返回一个安全的随机密钥,用于sodium_crypto_stream_xchacha20。
sodium_crypto_stream_xchacha20:将密钥和随机数扩展为伪随机字节的密钥流。
sodium_crypto_stream_xchacha20_xor:使用随机数和密钥(无身份验证)加密消息。
此外,在全局命名空间中定义了两个新的PHP常量:

SODIUM_CRYPTO_STREAM_XCHACHA20_KEYBYTES(分配32)
SODIUM_CRYPTO_STREAM_XCHACHA20_NONCEBYTES(分配24)
不过请谨慎使用。由于没有身份验证,解密操作容易受到常见的密文攻击。

您可以在GitHub页面上阅读有关其用法和要求的更多信息。

新的IntlDatePatternGenerator类
PHP的底层ICU库支持创建本地化的日期和时间格式,但不能完全自定义。

例如,如果您想在PHP 8.0之前创建特定于语言环境的数据和时间格式,您可以使用预定义的IntlDateFormatter常量以6种方式完成:

IntlDateFormatter::LONG:更长,例如November 10, 2017 or 11:22:33pm
IntlDateFormatter::MEDIUM:短一点,比如November 10, 2017
IntlDateFormatter::SHORT:只是数字,比如10/11/17 or 11:22pm
其中每一个也有自己的RELATIVE_变体,将日期格式设置在当前日期之前或之后的有限范围内。在 PHP 中,值是yesterday, today和tomorrow。

假设您想使用年份的长版本和月份的短版本,例如10/11/2017。但在PHP 8.0,你不能这样做。

在PHP 8.1+中,您可以使用新的IntlDatePatternGenerator类指定日期、月份和时间使用的格式。您可以将这些组件的确切顺序留给格式化程序。

您应该注意到,虽然这个类中只有Date一词,但它与ICU的DateTimePatternGenerator一致。这意味着您还可以使用它来创建灵活的时间格式。为了简化命名,PHP团队选择使用较短的IntlDatePatternGenerator术语。

这是直接来自其RFC的示例:

复制
$skeleton = "YYYYMMdd";
$today = \DateTimeImmutable::createFromFormat('Y-m-d', '2021-04-24');
$dtpg = new \IntlDatePatternGenerator("de_DE");
$pattern = $dtpg->getBestPattern($skeleton);
echo "de: ", \IntlDateFormatter::formatObject($today, $pattern, "de_DE"), "\n";
$dtpg = new \IntlDatePatternGenerator("en_US");
$pattern = $dtpg->getBestPattern($skeleton), "\n";
echo "en: ", \IntlDateFormatter::formatObject($today, $pattern, "en_US"), "\n";
/*
de: 24.04.2021
en: 04/24/2021
*/
在上面的代码中,skeleton变量定义了要使用的特定日期或时间格式。但是,格式化程序处理最终结果的顺序。

支持AVIF图像格式
AVIF或AV1图像文件格式,是一种基于AV1视频编码格式的相对较新的免版税图像格式。除了提供更高的压缩率(因此文件更小)之外,它还支持多种特性,例如透明度、HDR等。

AVIF格式最近才标准化(2021年6月8日)。这为Chrome 85+和Firefox 86+等浏览器增加了对AVIF图像的支持铺平了道路。

PHP 8.1的图像处理和GD扩展增加了对AVIF图像的支持。

但是,要包含此特性,您需要编译具有AVIF支持的GD扩展。您可以通过运行以下命令来执行此操作。

对于Debian/Ubuntu:

复制
apt install libavif-dev
对于Fedora/RHEL:

复制
dnf install libavif-devel
这将安装所有最新的依赖项。接下来,您可以通过--with-avif使用./configure脚本运行标志来编译AVIF支持。

复制
./buildconf --force
./configure --enable-gd --with-avif
如果您要从头开始一个新环境,您还可以在此处启用其他PHP扩展。

安装后,您可以通过在PHP终端中运行以下命令来测试是否启用了AVIF支持:

复制
php -i | grep AVIF
如果您已正确安装AVIF,您将看到以下结果:

复制
AVIF Support => enabled
您还可以使用gd_info()调用来检索GD功能列表,包括是否启用了AVIF支持功能。

这个更新的PHP 8.1 GD扩展还添加了两个用于处理AVIF图像的新函数:imagecreatefromavif和imageavif. 它们的工作方式与JPEG和PNG对应物类似。

imagecreatefromavif函数从给定的AVIF图像返回一个GdImage实例。然后,您可以使用此实例来编辑或转换图像。

另一个imageavif函数输出AVIF图像文件。例如,您可以使用它将JPEG转换为AVIF:

复制
$image = imagecreatefromjpeg('image.jpeg');
imageavif($image, 'image.avif');
您可以在其GitHub页面上阅读有关此新特征的更多信息。

新的目录上传$_FILES: full_path键
PHP维护了大量预定义变量来跟踪各种事物。其中之一是$_FILES 变量保存通过HTTP POST方法上传的项目的关联数组。

大多数现代浏览器都支持使用HTML文件上传字段上传整个目录。甚至PHP<8.1也支持此功能,但有一个很大的警告。您无法上传具有确切目录结构或相对路径的文件夹,因为PHP没有将此信息传递给$_FILES数组。

这与另外一个名为新的关键的变化在PHP 8.1full_path的$_FILES阵列。使用这些新数据,您可以在服务器上存储相对路径或复制确切的目录结构。

您可以通过$FILES使用var_dump($_FILES);命令输出数组来测试此信息。

但是,如果您正在使用此功能,请谨慎操作。确保您防范标准文件上传攻击。

对字符串键控数组的数组解包支持
PHP 7.4添加了对使用数组展开运算符 ( … )进行数组解包的支持。它可以作为使用array_merge()函数的更快替代方法。但是,此特性仅限于数字键数组,因为在合并具有重复键的数组时,解包字符串键数组会导致冲突。

但是,PHP 8添加了对命名参数的支持,消除了这个限制。因此,数组解包现在也支持使用相同语法的字符串键数组:

复制
$array = [...$array1, ...$array2];
这个RFC示例说明了如何在PHP 8.1中处理合并具有重复字符串键的数组:

复制
$array1 = ["a" => 1];
$array2 = ["a" => 2];
$array = ["a" => 0, ...$array1, ...$array2];
var_dump($array); // ["a" => 2]
在这里,字符串键“a”在通过数组解包合并之前出现了三次。但只有它属于$array2的最后一个值获胜。

显式八进制数字表示法
PHP 支持各种数字系统,包括十进制 (base-10)、二进制 (base-2)、八进制 (base-8) 和十六进制 (base-16)。十进制数字系统是默认值。

如果你想使用任何其他数字系统,那么你必须在每个数字前加上一个标准前缀:

十六进制: 0x前缀。(例如 17 = 0x11)
二进制: 0b前缀。(例如 3 = 0b11)
八进制: 0前缀。(例如 9 = 011)
您可以看到八进制数字系统的前缀与其他系统的前缀有何不同。为了标准化这个问题,许多编程语言增加了对显式八进制数字符号的支持:0o或0O。

从PHP 8.1开始,您可以在八进制数字系统中将上述示例(即以10为基数的数字9)编写为0o11或0O11。

复制
0o16 === 14; // true
0o123 === 83; // true
0O16 === 14; // true
0O123 === 83; // true
016 === 0o16; // true
016 === 0O16; // true
此外,这个新特性也适用于PHP 7.4中引入的下划线数字文字分隔符。

在其RFC中阅读有关此新PHP 8.1特征的更多信息。

MurmurHash3和xxHash哈希算法支持
PHP 8.1添加了对MurmurHash3和xxHash散列算法的支持。它们不是为加密用途而设计的,但它们仍然提供令人印象深刻的输出随机性、分散性和唯一性。

这些新的散列算法比大多数PHP现有的散列算法都快。事实上,其中一些散列算法的变体比RAM吞吐量更快。

由于PHP 8.1还增加了对声明特定于算法的$options参数的支持,您可以对这些新算法执行相同的操作。这个新参数的默认值为[]。因此,它不会影响我们现有的任何哈希函数。

您可以在他们的GitHub页面上阅读有关这些PHP 8.1新功能的更多信息:MurmurHash3、xxHash、Algorithm-specific $options.

DNS-over-HTTPS (DoH) 支持
DNS-over-HTTPS (DoH) 是一种通过HTTPS协议进行DNS解析的协议。DoH使用HTTPS加密客户端和DNS解析器之间的数据,通过防止中间人攻击来提高用户隐私和安全性。

从PHP 8.1开始,您可以使用Curl扩展来指定DoH服务器。它需要使用libcurl 7.62+版本编译PHP。对于大多数流行的操作系统(包括Linux发行版)来说,这不是问题,因为它们通常包含Curl 7.68+。

您可以通过指定CURLOPT_DOH_URL选项来配置DoH服务器URL 。

复制
$doh = curl_init('https://www.wbolt.com');
curl_setopt($doh, CURLOPT_DOH_URL, 'https://dns.google/dns-query');
curl_exec($doh);
在上面的示例中,我们使用了Google的公共DNS服务器。另外,请注意https://在所有使用的URL中的使用。确保完美地配置它,因为在Curl中没有可以回退的默认DNS服务器。

您还可以从Curl文档中包含的公共DoH服务器列表中进行选择。

此外,Curl文档的CURLOPT_DOH_URL 参考解释了如何彻底使用其各种参数。

使用CURLStringFile从字符串上载文件
PHP Curl扩展支持带有文件上传的HTTP(S)请求。它使用CURLFile类来实现这一点,该类接受URI或文件路径、mime类型和最终文件名。

但是,使用CURLFile类,您只能接受文件路径或URI,而不能接受文件本身的内容。如果您已经将文件上传到内存中(例如处理过的图像、XML文档、PDF),您必须使用data://Base64编码的URI。

但是libcurl已经支持一种更简单的方式来接受文件的内容。新的CURLStringFile类增加了对此的支持。

您可以阅读其GitHub页面以了解有关如何在PHP 8.1中实现的更多信息。

新的MYSQLI_REFRESH_REPLICA常数
PHP 8.1的mysqli扩展添加了一个名为MYSQLI_REFRESH_REPLICA. 它相当于现有的MYSQLI_REFRESH_SLAVE常数。

这个变化在MySQL 8.0.23中受到欢迎,以解决技术词汇中的种族不敏感问题(最常见的例子包括“奴隶”和“主人”)。

您应该注意到旧的常量没有被删除或弃用。开发人员和应用程序可以继续使用它。对于希望抛弃此类术语的开发人员和公司而言,此新常量只是一种选择。

使用继承缓存提高性能
继承缓存(Inheritance Cache )是opcache的新增功能,可消除PHP类继承开销。

PHP类由opcache单独编译和缓存。但是,它们已经在运行时针对每个请求进行了链接。这个过程可能涉及几个兼容性检查和从父类和特征借用方法/属性/常量。

因此,即使每个请求的结果都相同,这仍需要相当长的时间来执行。

继承缓存链接所有唯一的依赖类(父类、接口、特征、属性类型、方法)并将结果存储在opcache共享内存中。由于这种情况现在只发生一次,因此继承需要较少的指令。

此外,它消除了对不可变类的限制,例如未解析的常量、类型化属性和协变类型检查。因此,存储在opcache中的所有类都是不可变的,进一步减少了所需的指令数量。

总而言之,它有望带来显着的性能优势。该补丁的作者Dimitry Stogov发现它在基础Symfony “Hello, World!” 上有8%的改进。程序。我们迫不及待地想在我们的以下PHP基准测试中测试它。

First-Class可调用语法
PHP 8.1添加了First-Class可调用语法来取代使用字符串和数组的现有编码。除了创建更干净的Closure 之外,静态分析工具也可以访问这种新语法并尊重声明的范围。

以下是一些取自RFC的示例:

复制
$fn = Closure::fromCallable('strlen');
$fn = strlen(...);
$fn = Closure::fromCallable([$this, 'method']);
$fn = $this->method(...)
$fn = Closure::fromCallable([Foo::class, 'method']);
$fn = Foo::method(...);
这里,所有的表达式对都是等价的。三点 ( … ) 语法类似于参数解包语法 ( ...$args)。除了这里,参数尚未填写。

PHP 8.1中的变化
PHP 8.1 还包括对其现有语法和功能的更改。让我们来讨论它们:

PHP Interactive Shell需要readline扩展
MySQLi默认错误模式设置为异常
CSV写入函数的可定制行尾
新version_compare运算符限制
HTML编码和解码函数现在使用ENT_QUOTES | ENT_SUBSTITUTE
关于非法紧凑函数调用的警告
新的从资源到类对象的迁移
PHP Interactive Shell需要readline扩展
PHP的readline扩展支持交互式shell功能,例如导航、自动完成、编辑等。虽然它与PHP捆绑在一起,但默认情况下并未启用。

您可以使用PHP CLI的-a命令行选项访问PHP交互式shell:

复制
php -a
Interactive shell
php >
php > echo "Hello";
Hello
php > function test() {
php { echo "Hello";
php { }
php > test();
Hello
在PHP 8.1之前,即使没有启用readline扩展,您也可以使用PHP CLI打开交互式shell 。正如预期的那样,shell的交互功能不起作用,使该-a选项变得毫无意义。

在PHP 8.1 CLI中,如果您没有启用readline扩展,交互式shell会退出并显示错误消息。

复制
php -a
Interactive shell (-a) requires the readline extension.
MySQLi默认错误模式设置为异常
在PHP 8.1之前,MySQLi默认为静默错误。这种行为通常会导致代码不遵循严格的错误/异常处理。开发人员必须实现自己的显式错误处理功能。

PHP 8.1通过将MySQLi的默认错误报告模式设置为抛出异常来更改此行为。

复制
Fatal error: Uncaught mysqli_sql_exception: Connection refused in ...:...
由于这是一个重大更改,对于PHP<8.1版本,您应该mysqli_report在建立第一个MySQLi连接之前使用该函数显式设置错误处理模式。或者,您可以通过实例化一个mysqli_driver实例来选择错误报告值来执行相同的操作。

RFC遵循PHP 8.0中引入的类似更改。

CSV写入函数的可定制行尾
在PHP 8.1之前,PHP的内置CSV写入函数fputcsv和SplFileObject::fputcsv被硬编码为\n 在每行末尾添加(或换行符)。

PHP8.1为这些函数添加了对名为eol的新参数的支持。您可以使用它来传递可配置的行尾字符。默认情况下,它仍然使用\n 字符。因此,您可以继续在现有代码中使用它。

标准字符转义规则适用于使用行尾字符。如果您想使用\r、\n或\r\n作为EOL字符,您必须将它们括在双引号中。

这是跟踪此新更改的GitHub页面。

新的 version_compare 运算符限制
PHP的version_compare()函数比较两个版本号字符串。此函数接受一个可选的第三个参数,operator用于测试特定关系。

尽管文档中没有明确说明,但在PHP 8.1之前,您可以将此参数设置为部分值(例如g, l, n)而不会出现错误。

PHP 8.1对version_compare()函数的operator参数添加了更严格的限制来克服这种情况。您现在可以使用的唯一运算符是:

==、=和eq
!=、<>和ne
>和gt
>=和ge
<和lt
<=和le
没有更多的部分运算符值。

HTML编码和解码函数改用 ENT_QUOTES | ENT_SUBSTITUTE
HTML实体是字符的文本表示,否则会被解释为HTML。想想诸如<和>用于定义HTML 标签的字符(例如<a>、<h3>、<script>)。

HTML实体<是& lt;(小于符号)和>是& gt;(大于符号)。

注意:删除“&”和“amp”之间的空格。

您可以在HTML文档中安全地使用这些HTML实体,而无需触发浏览器的渲染引擎。

例如,& lt;script& gt;将在浏览器中显示为<script>,而不是被解释为HTML标记。

之前PHP 8.1,则用htmlspecialchars()和 htmlentities() 函数转换如 “, <, >和& 符号为各自的HTML实体。但默认情况下,他们没有将单引号字符 (') 转换为其HTML实体。此外,如果文本中存在格式错误的 UTF-8,它们将返回一个空字符串。

在PHP 8.1中,这些HTML编码和解码函数(及其相关函数)也会默认将单引号字符转换为它们的HTML实体。

如果给定的文本包含无效字符,函数将用Unicode替换字符 (�) 替换它们,而不是返回空字符串。PHP 8.1通过默认将这些函数的签名更改为ENT_QUOTES | ENT_SUBSTITUTE而不是ENT_COMPAT来实现这一点。

大多数框架已经ENT_QUOTES用作默认标志值。因此,由于此更改,您不会看到太大差异。然而,新ENT_SUBSTITUTE标志并没有被广泛使用。PHP 8.1将导致无效的UTF-8字符被替换为 � 字符而不是返回空字符串。

关于非法紧凑函数调用的警告
PHP 的compact()函数超级好用。您可以使用它来创建一个数组,其中包含使用名称和值的变量。

例如,考虑以下代码:

复制
$animal = 'Cat';
$sound = 'Meow';
$region = 'Istanbul';
compact('animal', 'sound', 'region');
// ['animal' => "Cat", 'sound' => "Meow", 'region' => "Istanbul"]
紧凑型函数的文档指出,这将只接受字符串参数或字符串值数组值。但是,在PHP 7.3之前,任何未设置的字符串都将被悄悄跳过。

PHP7.3修改了compact()函数,以便在使用未定义变量时发出通知。PHP 8.1更进一步,并发出警告。

您可以阅读其GitHub 页面以了解此更改是如何发生的。

新的从资源到类对象迁移
PHP的长期目标之一是从资源转向标准类对象。

由于历史原因,资源对象在PHP应用程序中被广泛使用。因此,资源向类对象的迁移需要尽可能减少破坏性。PHP 8.1迁移了五个这样的资源:

将file_info资源迁移到finfo对象

PHP的finfo 类为函数提供了一个面向对象的接口fileinfo。但是,使用finfo函数返回resource具有file_info类型的对象而不是finfo类本身的实例。

PHP 8.1修复了这个异常。

迁移到IMAP\Connection类对象的IMAP资源

根据资源到对象的迁移目标,当PHP最终修改类的实现细节时,新的IMAP\Connection类将潜在的破坏性更改降至最低。

这个新类也被声明final,所以你不被允许extend。

在其GitHub页面上阅读有关其实现的更多信息。

FTP连接资源现在为FTP\Connection类对象

在PHP<8.1中,如果您使用或函数ftp_connect()或者ftp_ssl_connect()创建FTP连接,您将返回一个ftp类型的资源对象。

PHP 8.1添加了新的FTP\Connection类来纠正这个问题。和IMAP\Connection类一样,它也被声明final为防止它被扩展。

在其GitHub页面上阅读有关其实现的更多信息。

字体标识符迁移到GdFont类对象

PHP的GD扩展提供了imageloadfont() 函数来加载用户定义的位图并返回其字体标识符资源 ID(一个整数)。

在PHP 8.1中,此函数将改为返回GdFont类实例。此外,为了使迁移轻松自如,以前从imageloadfont()接受资源ID的所有函数现在都将采用新的GdFont类对象。

在其GitHub页面上阅读有关此迁移的更多信息。

LDAP资源迁移到对象

LDAP或轻量级目录访问协议,用于访问“目录服务器”。就像硬盘目录结构一样,它是一个独特的数据库,以树状结构保存数据。

PHP包含一个LDAP扩展,它接受或返回PHP 8.1之前的资源对象。但是,它们现在都已无缝迁移到新的类实例。已经过渡的资源类型有:

ldap link资源到\LDAP\Connection类对象
ldap result资源到\LDAP\Result类对象
ldap result entry资源到\LDAP\ResultEntry类对象
浏览其GitHub页面以更好地了解此迁移。

Pspell资源现在为类对象

PHP的Pspell扩展允许您检查拼写和单词建议。

PHP<8.1使用pspell和pspell config带有整数标识符的资源对象类型。这两个资源对象现在替换为PSpell\Dictionary和PSpell\Config类对象。

与之前的迁移一样,之前接受或返回资源对象标识符的所有Pspell函数都将采用新的类对象实例。

有关更多信息,请参阅其GitHub页面。

PHP 8.1中的弃用
PHP 8.1弃用了许多以前的功能。以下列表简要概述了PHP 8.1弃用的功能:

不能将null传递给不可为Null的内部函数参数
受限制的$GLOBALS使用
内部函数的返回类型声明
不推荐使用可序列化接口
不兼容的float到int转换已弃用
mysqli::get_client_info方法和mysqli_get_client_info($param) 已弃用
不推荐使用所有mhash*() 函数(散列扩展)
filter.default和filter.default_options INI设置已弃用
在false上弃用autovivification
不推荐使用mysqli_driver->driver_version属性
不能将null 传递给不可为Null的内部函数参数
从PHP 8.0开始,它的内部函数null即使对于不可为null的参数也默默地接受值。这不适用于用户定义的函数——它们只接受null可为空的参数。

例如,考虑这种用法:

复制
var_dump(str_contains("foobar", null));
// bool(true)
在这里,null值被静默转换为空字符串。因此,结果返回true。

该RFC旨在通过在PHP 8.1中抛出弃用警告来同步内部函数的行为。

复制
var_dump(str_contains("foobar", null));
// Deprecated: Passing null to argument of type string is deprecated
在下一个主要的 PHP 版本(即 PHP >=9.0)中,弃用将成为 TypeError,使内部函数的行为与用户定义的函数保持一致。

限制$GLOBALS使用
PHP的$GLOBALS变量提供对其内部符号表的直接引用。支持此功能很复杂,并且会影响阵列操作性能。另外,它很少被使用。

根据RFC,$GLOBALS不再允许间接修改。此更改向后不兼容。

这种变化的影响相对较低:

在前2k个composer包中,我发现了23个使用 $GLOBALS而不直接取消引用它的案例。根据粗略的检查,只有两种情况没有以只读方式使用$GLOBALS。

但是,只读用法$GLOBALS继续照常工作。不再支持的是$GLOBALS整体写入。因此,您可能会遇到轻微的性能提升,尤其是在使用普通PHP数组时。

内部函数的返回类型声明
PHP 8.0允许开发人员为大多数内部函数和方法声明参数和返回类型。这要归功于各种RFC,例如内部函数的一致类型错误、联合类型2.0和混合类型v2。

但是,在很多情况下可能会丢失类型信息。其中一些包括具有资源型,out pass-by-ref 参数,非final方法返回类型,函数或不按一般规则解析参数的方法。您可以在其RFC中阅读确切的详细信息。

此RFC仅解决非最终方法的返回类型的问题。然而,PHP团队并没有立即完全淘汰它,而是提供了一个渐进的迁移路径,以使用相关的方法返回类型更新您的代码库。

非最终的内部方法返回类型(如果可能)在PHP 8.1中暂时声明,它们将在PHP 9.0中强制执行。这意味着在PHP 8.x版本中,当内部方法以返回类型不兼容的方式被覆盖时,在继承检查期间会引发“弃用”通知,而PHP 9.0会使这些成为致命错误。

如果您在更新到PHP 8.1后看到此弃用通知,请确保更新您的方法的返回类型。

不推荐使用可序列化接口
PHP 7.4通过两个新的魔术方法引入了自定义对象序列化机制:__serialize()和__unserialize(). 这些新方法旨在最终替换损坏的Serializable接口。

该RFC提议通过制定最终删除Serializable的计划来最终确定该决定。

在PHP 8.1中,如果你在没有实现和方法的情况下实现了Serializable接口,PHP将抛出“Deprecated”警告。

在PHP8.1中,如果在没有实现__serialize()和__unserialize()方法的情况下实现Serializable接口,PHP将抛出“Deprecated”警告。

复制
Deprecated: The Serializable interface is deprecated. Implement __serialize() and __unserialize() instead (or in addition, if support for old PHP versions is necessary) in ... on line ...
如果你支持PHP <7.4和PHP >=7.4,你应该实现Serializable接口和新的魔法方法。在PHP >=7.4版本上,魔术方法将优先。

不推荐使用不兼容的float 到int 转换
PHP是一种动态类型语言。因此,在很多情况下自然会发生类型强制。大多数这些强制是无害的,而且超级方便。

但是,当浮点数转换为整数时,通常会涉及数据丢失。例如,当浮点数3.14转换为整数3时,它会丢失其小数值。

当浮点数超出平台整数范围或浮点数字符串转换为整数时,也会发生同样的情况。

PHP 8.1纠正了这种行为,并使其动态类型强制更符合大多数现代编程语言。目标是使这种强制可预测和直观。

在PHP 8.1中,当不兼容的float被隐式强制转换为int时,您将看到弃用通知。但是什么构成了整数兼容的浮点数?RFC对此做出了回答:

如果具有以下特征,则称浮点数与整数兼容:

是一个数字(即不是 NaN 或无穷大)
在PHP整数范围内(取决于平台)
没有小数部分
此弃用通知将在下一个主要PHP版本(即PHP 9.0)中升级为TypeError。

mysqli::get_client_info和mysqli_get_client_info($param)方法已过时
MySQL客户端API定义了两个常量:client_info(字符串)和client_version(整数)。MySQL Native Driver (MySQLnd) 是官方PHP源代码的一部分,并将这些常量与PHP版本挂钩。在libmysql中,它们代表编译时的客户端库版本。

在PHP8.1之前,mysqli以4种方式公开这些常量:mysqli_driver属性、mysqli 属性、mysqli_get_client_info()函数和mysqli::get_client_info方法。但是,对于client_version没有方法。

MySQLnd 以两种方式向PHP公开这些常量:常量和函数调用。为了统一使用这两个选项的mysqli访问方法,PHP 8.1弃用了其他两个选项:

get_client_infomysqli类中的方法。相反,您可以只使用该mysqli_get_client_info()函数。
mysqli_get_client_info()带参数的函数。不带任何参数调用函数以避免弃用通知。
在其GitHub 页面上阅读有关此弃用的更多信息。

不推荐使用所有mhash*()函数(散列扩展)
PHP5.3将mhash*()函数集成到ext/hash中,作为ext/mhash的兼容层。后来,PHP7.0删除了ext/mhash。

与hash_*()函数不同,mhash*()函数并不总是可用。您必须在配置PHP时单独启用它们。

在PHP 7.4中,散列扩展与PHP捆绑在一起,使其成为PHP的默认扩展。但是,--enable-mhash出于兼容性原因,它仍然支持启用该选项。

PHP团队决定在PHP 8.1中弃用mhash*()函数,并在PHP 9.0中完全删除它们。不推荐使用的函数是mhash(),mhash_keygen_s2k(),mhash_count(),mhash_get_block_size()和mhash_get_hash_name()。您可以使用标准ext/hash功能代替它们。

filter.default和filter.default_optionsINI设置已过时
PHP的filter.defaultINI设置允许您将过滤器适用于所有的PHP超全局-即GPCR的数据($_GET,$_POST,$_COOKIE,$_REQUEST,和$_SERVER)。

例如,您可以设置filter.default=magic_quotes或filter.default=add_slashes(基于PHP版本)来复活PHP有争议且不安全的魔术引号功能(在PHP 5.4中删除)。

filter.default的INI设置提供了额外的功能,允许使用更多的过滤器,使情况变得更糟。例如,它的另一个选项-filter.default=special_chars -只为HTML启用魔法引号。人们对这些设置的了解要少得多。

如果filter.default 设置为除unsafe_raw(默认值)以外的任何值,PHP8.1将抛出一个弃用警告。您不会看到ilter.default_options的单独弃用通知,但PHP9.0将删除这两个INI设置。

作为替代方案,您可以开始使用filter_var()函数。它使用指定的过滤器过滤变量。

弃用autovivification的false
PHP允许自动激活(从假值自动创建数组)。如果变量未定义,此功能非常有用。

尽管如此,当值为false或null时自动创建数组并不理想。

此RFC不允许从错误值自动激活。但是,请注意,仍然允许来自未定义变量和null的自动激活。

在PHP 8.1中,附加到false类型的变量将发出弃用通知:

复制
Deprecated: Automatic conversion of false to array is deprecated in
PHP 9.0同样会抛出致命错误,这与其他标量类型相同。

mysqli_driver->driver_version属性已弃用
MySQLi 扩展的mysqli_driver->driver_version属性已经13年没有更新了。尽管此后对驱动程序进行了许多更改,但它仍然返回旧的驱动程序版本值,使该属性变得毫无意义。

在PHP 8.1中,mysqli_driver->driver_version属性已弃用。

其他小改动
PHP 8.1中有更多的弃用。将它们全部列出在这里将是一项令人筋疲力尽的工作。我们建议您直接查看RFC以了解这些较小的弃用情况。

PHP的GitHub页面还包括一​​个PHP 8.1升级说明指南。它列出了在升级到PHP 8.1之前您应该考虑的所有重大更改。

小结
PHP 8.1离我们不远了。并且它已经承诺将其前身提升一倍,这是不小的壮举。

我们认为最令人兴奋的PHP 8.1特性是枚举、纤维、纯交集类型及其许多性能改进。此外,我们迫不及待地要让PHP 8.1步入正轨,并对各种PHP框架和CMS进行基准测试。

===========php8===========

===================================Php8================================================
1.联合类型
PHP7

class Number {
/** @var int|float */
private $number;
/**
* @param float|int $number
*/
public function __construct($number) {
$this->number = $number;
}
}
new Number('NaN'); // Ok
PHP8

class Number {
public function __construct(
private int|float $number
) {}
}
new Number('NaN'); // TypeError

2.mixed类型
mixed本身是以下类型之一:

array
bool
callable
int
float
null
object
resource
string
注意,mixed也可以用作参数或属性类型,而不仅仅是返回类型。

另外由于mixed已经包含null,因此不允许将其设置为nullable。以下内容将触发错误

3.JIT作为PHP底层编译引擎,对于PHP8的性能贡献是非常之大,不过对于常规WEB应用来说,优势不明显,但仍然是非常的高大上特性,是PHP8的扛鼎之作
4.最实用的特性:构造器属性提升、Nullsafe运算符、str_contains()、 str_starts_with()、 str_ends_with()
5.构造器属性提升
代替如下代码:

class Money
{
public Currency $currency;

public int $amount;

public function __construct(
Currency $currency,
int $amount,
) {
$this->currency = $currency;
$this->amount = $amount;
}
}
你可以这样做:

class Money
{
public function __construct(
public Currency $currency,
public int $amount,
) {}
}

6.nullsafe运算符
现在可以用新的 nullsafe 运算符链式调用,而不需要条件检查 null。 如果链条中的一个元素失败了,整个链条会中止并认定为 Null。

$country =null;
if ($session !== null) {
$user = $session->user;
if ($user !== null) {
$address = $user->getAddress();

if ($address !== null) {
$country = $address->country;
}
}
}
简化为一行代码

$country = $session?->user?->getAddress()?->country;

7.确实是有点酷

str_contains()、str_starts_with()和str_ends_with()函数
有些人可能会说它早就该有了,但我们终于不必再依赖strpos() 来知道字符串是否包含另一个字符串了。

代替如下:

if (strpos('string with lots of words', 'words') !== false) { /* … */ }
你可以这样做

if (str_contains('string with lots of words', 'words')) { /* … */ }
感觉大多数场景应该是不需要使用strpos了吧,外两个早就应该有了,str_starts_with()和str_ends_with()这两个函数现在能省事不少。

str_starts_with('haystack', 'hay'); // true
str_ends_with('haystack', 'stack'); // true

8.最具潜力的特性:注解、Match表达式、WeakMap
现在可以用原生的PHP语法来使用结构化的元数据,而不需要再依赖PHPDoc解析,性能也随之提升。之前定义注解路由可能需要使用:

class PostsController
{
/**
* @Route("/api/posts/{id}", methods={"GET"})
*/
public function get($id) { /* ... */ }
}
现在你可以直接用PHP的注解语法来定义,并通过反射直接获取

class PostsController
{
#[Route("/api/posts/{id}", methods: ["GET"])]
public function get($id) { /* ... */ }
}

9.Match表达式
你可以称它为switch表达式的大哥:match可以返回值,不需要break语句,可以组合条件,使用严格的类型比较,并且不执行任何类型的强制。

如下所示:

$result = match($input) {
0 => "hello",
'1', '2', '3' => "world",
};

10.WeakMap
WeakMap保留对对象的引用,这些引用不会阻止这些对象被垃圾回收。
特别是在 ORM 的情况下,它可以管理请求中的数百个,如果不是数千个实体;weak maps可以提供更好、更资源友好的处理这些对象的方法。
下面是weak maps的示例:

class Foo
{
private WeakMap $cache;

public function getSomethingWithCaching(object $obj): object
{
return $this->cache[$obj]
??= $this->computeSomethingExpensive($obj);
}
}

11其它特性
php7  0 == 'foobar' // 返回true
php8  0 == 'foobar' // 返回false

可以在对象上使用::class   $foo = new Foo();   var_dump($foo::class);  现在可以对对象使用::class,它的工作方式与 get_class() 相同。

12.traits 中的抽象方法改进 Traits 可以指定抽象方法,这些方法必须由使用它们的类实现。在PHP8,必须保持一致的方法定义,包括参数类型和返回类型。

==========php7.4==========

====================================7.4=========================================
1、属性值类型声明

<?php

class User {

public int $id;

public string $name;

}

2、箭头函数

<?php

$factor = 10;

$nums = array_map(fn($n) => $n * $factor, [1, 2, 3, 4]);

// $nums = array(10, 20, 30, 40);

3、空值连写赋值运算符

<?php

$array['key'] ??= computeDefault();

// is roughly equivalent to

if (!isset($array['key'])) {

$array['key'] = computeDefault();

}

4、数组内展开
<?php

$parts = ['apple', 'pear'];

$fruits = ['banana', 'orange', ...$parts, 'watermelon'];

// ['banana', 'orange', 'apple', 'pear', 'watermelon'];

5、数值型字面量分隔符

<?php

6.674_083e-11; // float

299_792_458; // decimal

0xCAFE_F00D; // hexadecimal

0b0101_1111; // binary

6、弱引用

引用对象使其不被销毁

7、__toString()方法允许跑出异常


=======php7.2==========

====================================php7.2======================================
1、Nullable类型
参数以及返回值的类型通过在类型前加上一个问号使之允许为空
<?php
function testReturn(): ?string
{
return 'elePHPant';
}
var_dump(testReturn());
function testReturn(): ?string
{
return null;
}
var_dump(testReturn());
function test(?string $name)
{
var_dump($name);
}
test('elePHPant');
test(null);
test();
2、Void 函数
方法要么干脆省去 return 语句,要么使用一个空的 return 语句。
对于 void 函数来说,NULL 不是一个合法的返回值。
<?php
function swap(&$left, &$right) : void
{
if ($left === $right) {
return;
}
$tmp = $left;
$left = $right;
$right = $tmp;
}

$a = 1;
$b = 2;
var_dump(swap($a, $b), $a, $b);
3、对称性数组解构
短数组语法([])现在作为list()语法的一个备选项,可以用于将数组的值赋给一些变量(包括在foreach中)
<?php

$data = [
[1, 'Tom'],
[2, 'Fred'],
];
// list() style
list($id1, $name1) = $data[0];
// [] style

[$id1, $name1] = $data[0];
// list() style

foreach ($data as list($id, $name)) {
// logic here with $id and $name
}
// [] style

foreach ($data as [$id, $name]) {
// logic here with $id and $name
}
4、类常量可见性
<?php
class ConstDemo
{
const PUBLIC_CONST_A = 1;
public const PUBLIC_CONST_B = 2;
protected const PROTECTED_CONST = 3;
private const PRIVATE_CONST = 4;
}
5、iterable 伪类
<?php

function iterator(iterable $iter)
{

foreach ($iter as $val) {

//

}

}

6、多异常捕获处理

<?php

try {
// some code

} catch (FirstException | SecondException $e) {
// handle first and second exceptions
}

7、list()现在支持键名
这意味着它可以将任意类型的数组 都赋值给一些变量

<?php

$data = [
["id" => 1, "name" => 'Tom'],
["id" => 2, "name" => 'Fred'],
];

// list() style

list("id" => $id1, "name" => $name1) = $data[0];

// [] style

["id" => $id1, "name" => $name1] = $data[0];
// list() style

foreach ($data as list("id" => $id, "name" => $name)) {
// logic here with $id and $name
}

// [] style

foreach ($data as ["id" => $id, "name" => $name]) {
// logic here with $id and $name
}

8、支持为负的字符串偏移量
一个负数的偏移量会被理解为一个从字符串结尾开始的偏移量。
<?php

var_dump("abcdef"[-2]);

var_dump(strpos("aabbcc", "b", -3));

7.2
1、新的object类型
这种新的类型 object, 引进了可用于逆变(contravariant)参数输入和协变(covariant)返回任何对象类型。
<?php
function test(object $obj) : object
{
return new SplQueue();
}

test(new StdClass());
2、通过名称加载扩展

使用 dl() 函数进行启用

3、允许重写抽象方法(Abstract method)

<?php

abstract class A
{
abstract function test(string $s);

}
abstract class B extends A
{
// overridden - still maintaining contravariance for parameters and covariance for return
abstract function test($s) : int;
}

4、扩展了参数类型

重写方法和接口实现的参数类型现在可以省略了。不过这仍然是符合LSP,因为现在这种参数类型是逆变的。

<?php

interface A

{

public function Test(array $input);

}

class B implements A

{

public function Test($input){} // type omitted for $input

}

5、允许分组命名空间的尾部逗号

<?php

use Foo\Bar\{

Foo,

Bar,

Baz,

};
6、更灵活的Heredoc 与 Nowdoc 语法
7、数组的解构支持引用赋值
[&$a, [$b, &$c]] = $d
8、Instanceof 运算符支持字面量

判断结果总是 FALSE
9、允许函数和方法被调用时参数最后的空逗号收尾

10、多字节字符串的相关函数

mb_convert_case():

mb_strtolower())

mb_strtoupper())

<?php

mb_ereg('(?<word>\w+)', '国', $matches);

// => [0 => "国", 1 => "国", "word" => "国"];

<?php

mb_ereg_replace('\s*(?<word>\w+)\s*', "_\k<word>_\k'word'_", ' foo ');

// => "_foo_foo_"

========php7.0==========

=========================================Php7==============================================
参数类型声明
标量类型声明 有两种模式: 强制 (默认) 和 严格模式。
现在可以使用下列类型参数(无论用强制模式还是严格模式):
字符串(string),
整数 (int),
浮点数 (float),
以及布尔值 (bool)。
它们扩充了PHP5中引入的其他类型:类名,接口,数组和 回调类型。
<?php
// Coercive mod
function sumOfInts(int ...$ints)
{
return array_sum($ints);
}
var_dump(sumOfInts(2, '3', 4.1));
2、返回值类型声明
返回类型声明指明了函数返回值的类型。可用的类型与参数声明中可用的类型相同。
<?php
function arraysSum(array ...$arrays): array
{
return array_map(function(array $array): int {
return array_sum($array);

}, $arrays);

}
print_r(arraysSum([1,2,3], [4,5,6], [7,8,9]));
3、null合并运算符
如果变量存在且值不为NULL, 它就会返回自身的值,否则返回它的第二个操作数。
<?php
// Fetches the value of $_GET['user'] and returns 'nobody'
// if it does not exist.
$username = $_GET['user'] ?? 'nobody';
// This is equivalent to:
$username = isset($_GET['user']) ? $_GET['user'] : 'nobody';
// Coalesces can be chained: this will return the first
// defined value out of $_GET['user'], $_POST['user'], and
// 'nobody'.
$username = $_GET['user'] ?? $_POST['user'] ?? 'nobody';
?>
4、太空船操作符(组合比较符)
用于比较两个表达式。当$a小于、等于或大于$b时它分别返回-1、0或1

<?php

// 整数
echo 1 <=> 1; // 0
echo 1 <=> 2; // -1
echo 2 <=> 1; // 1
// 浮点数
echo 1.5 <=> 1.5; // 0
echo 1.5 <=> 2.5; // -1
echo 2.5 <=> 1.5; // 1
// 字符串
echo "a" <=> "a"; // 0
echo "a" <=> "b"; // -1
echo "b" <=> "a"; // 1
5、通过 define() 定义常量数组
在 PHP5.6 中仅能通过 const 定义。
<?php
define('ANIMALS', [
'dog'
'cat',
'bird'
]);
echo ANIMALS[1]; // 输出 "cat"
6、匿名类

<?php
interface Logger {
public function log(string $msg);

}
class Application {
private $logger;
public function getLogger(): Logger {
return $this->logger;
}
public function setLogger(Logger $logger) {

$this->logger = $logger
}

}
$app = new Application;

$app->setLogger(new class implements Logger {
public function log(string $msg) {
echo $msg;
}

});
var_dump($app->getLogger());
7、Unicode codepoint 转译语法
接受一个以16进制形式的 Unicode codepoint,并打印出一个双引号或heredoc包围的 UTF-8 编码格式的字符串
echo "\u{aa}";
echo "\u{0000aa}";
echo "\u{9999}";
8、Closure::call()

简短干练的暂时绑定一个方法到对象上闭包并调用它。

<?php
class A {private $x = 1;}

// PHP 7 之前版本的代码

$getXCB = function() {return $this->x;};
$getX = $getXCB->bindTo(new A, 'A'); // 中间层闭包
echo $getX();
// PHP 7+ 及更高版本的代码
$getX = function() {return $this->x;};

echo $getX->call(new A);
9、为unserialize()提供过滤
通过白名单的方式来防止潜在的代码注入。
<?php
// 将所有的对象都转换为 __PHP_Incomplete_Class 对象
$data = unserialize($foo, ["allowed_classes" => false]);
// 将除 MyClass 和 MyClass2 之外的所有对象都转换为 __PHP_Incomplete_Class 对象
$data = unserialize($foo, ["allowed_classes" => ["MyClass", "MyClass2"]);
// 默认情况下所有的类都是可接受的,等同于省略第二个参数
$data = unserialize($foo, ["allowed_classes" => true]);

10、断言
assert()现在是一个语言结构,它允许第一个参数是一个表达式,而不仅仅是一个待计算的 string或一个待测试的boolean。
<?php
ini_set('assert.exception', 1);
class CustomError extends AssertionError {}
assert(false, new CustomError('Some error message'));
11、Group use declarations
从同一 namespace 导入的类、函数和常量现在可以通过单个 use 语句 一次性导入了。
// PHP 7+ 及更高版本的代码
use some\namespace\{ClassA, ClassB, ClassC as C};
use function some\namespace\{fn_a, fn_b, fn_c};
use const some\namespace\{ConstA, ConstB, ConstC};
12、生成器可以返回表达式
允许在生成器函数中通过使用 return 语法来返回一个表达式 (但是不允许返回引用值), 可以通过调用 Generator::getReturn() 方法来获取生成器的返回值, 但是这个方法只能在生成器完成产生工作以后调用一次。
<?php
$gen = (function() {
yield 1;
yield 2;
return 3;

})();
foreach ($gen as $val) {
echo $val, PHP_EOL;
}
echo $gen->getReturn(), PHP_EOL;

13、生成器委托
只需在最外层生成器中使用 yield from, 就可以把一个生成器自动委派给其他的生成器, Traversable 对象或者 array。
<?php
function gen()

{
yield 1;
yield 2;
yield from gen2();
}
function gen2()
{
yield 3;
yield 4;
}

foreach (gen() as $val)
{
echo $val, PHP_EOL;
}
14、整数除法函数 intdiv()
进行 整数的除法运算。
<?php
var_dump(intdiv(10, 3));

15、可以使用 list() 函数来展开实现了 ArrayAccess 接口的对象

 

==============PHP5.3==

1.支持命名空间(namespace)
2.通过static关键字,实现方法的延迟静态绑定
3.支持goto语句
4. 支持闭包匿名函数或Lambda函数array_map()或array_walk()等函数的回调函数
5. 两个魔术方法__callStatic()和__invoke()
6. 新增Nowdoc语法结构
7. const 关键字
8.三元省 expr1 ?: expr3
9. 静态成员或静态方法支持
10.支持try…catch

 

=========PHP5.4========

1新增traits  Traits提供了一种灵活的代码重用机制
2. 数组【】支持写法
3.支持函数方法数组化访问
5.加入webserver
6上传进度支持 $_SESSION[“upload_progress_name”]
7json_encode  可中文输出
8二进制直接量
9函数的参数类型
10. 废除了register_globals、 magic_quotes、 allow_call_time_pass_reference以及安全模式等等。
11. 早期 在早期版本中,你可以在函数调用时,在参数前添加&修饰符来指明参数变量按引用传递,你只需要在函数声明时指定按引用传递即可

 

==========Php5.5=======

新增Generator生成器yield
2. try…catch 新增了finally
3. foreach中支持嵌套list()结构
4..empty() 支持传入表达式,而不仅是一个变量
5. 非变量array或string也能支持下标访问
<?php echo array(1, 2, 3)[0]; echo [1, 2, 3][0]; echo "foobar"[0]; // 输出:11f
6. 新增密码哈希API
password_hash  password_verify
7.  新增 boolval() 函数
8. 新增 array_column() 函数二维数组中指定的列

 

======Php5.6====

1增强了const 常量 以前只能使用固定的值,现在允许常量计算,允许使用包含数字、字符串字面值和常量的表达式结果定义const常量,常量的值也可以为一个数组
2支持使用 … 运算符定义变长参数函数 实现变长
3 ** 进行幂运算 printf(2 ** 3); // 8  $a **= 3;
4命名空间 use 操作符支持函数和常量的导入 对应的结构为 use function 和 use const。
5. 解包功能
6. 上传超过2G的大文件
7. php://input 可以被复用
在 PHP 5.6 之前 php://input 打开的数据流只能读取一次; 数据流不支持 seek 操作
现在依赖于 SAPI 的实现,请求体数据被保存的时候, 它可以打开另一个 php://input 数据流并重新读取。 通常情况下,这种情况只是针对 POST 请求,而不是其他请求方式

 

 

 

 

分类: PHP


7种 实现web实时消息推送的方案(转)

0311lc.com说:

什么是消息推送(push)

推送的场景比较多,比如有人关注我的公众号,这时我就会收到一条推送消息,以此来吸引我点击打开应用。

消息推送(push)通常是指网站的运营工作等人员,通过某种工具对用户当前网页或移动设备APP进行的主动消息推送。

消息推送一般又分为web端消息推送移动端消息推送

上边的这种属于移动端消息推送,web端消息推送常见的诸如站内信、未读邮件数量、监控报警数量等,应用的也非常广泛。

在具体实现之前,咱们再来分析一下前边的需求,其实功能很简单,只要触发某个事件(主动分享了资源或者后台主动推送消息),web页面的通知小红点就会实时的+1就可以了。

通常在服务端会有若干张消息推送表,用来记录用户触发不同事件所推送不同类型的消息,前端主动查询(拉)或者被动接收(推)用户所有未读的消息数。

消息推送无非是推(push)和拉(pull)两种形式,下边我们逐个了解下。

短轮询

轮询(polling)应该是实现消息推送方案中最简单的一种,这里我们暂且将轮询分为短轮询长轮询

短轮询很好理解,指定的时间间隔,由浏览器向服务器发出HTTP请求,服务器实时返回未读消息数据给客户端,浏览器再做渲染显示。

一个简单的JS定时器就可以搞定,每秒钟请求一次未读消息数接口,返回的数据展示即可。

setInterval(() => {
  // 方法请求
  messageCount().then((res) => {
      if (res.code === 200) {
          this.messageCount = res.data
      }
  })
}, 1000);

效果还是可以的,短轮询实现固然简单,缺点也是显而易见,由于推送数据并不会频繁变更,无论后端此时是否有新的消息产生,客户端都会进行请求,势必会对服务端造成很大压力,浪费带宽和服务器资源。

长轮询

长轮询是对上边短轮询的一种改进版本,在尽可能减少对服务器资源浪费的同时,保证消息的相对实时性。长轮询在中间件中应用的很广泛,比如Nacosapollo配置中心,消息队列kafkaRocketMQ中都有用到长轮询。

Nacos配置中心交互模型是push还是pull?一文中我详细介绍过Nacos长轮询的实现原理,感兴趣的小伙伴可以瞅瞅。

这次我使用apollo配置中心实现长轮询的方式,应用了一个类DeferredResult,它是在servelet3.0后经过Spring封装提供的一种异步请求机制,直意就是延迟结果。

DeferredResult可以允许容器线程快速释放占用的资源,不阻塞请求线程,以此接受更多的请求提升系统的吞吐量,然后启动异步工作线程处理真正的业务逻辑,处理完成调用DeferredResult.setResult(200)提交响应结果。

下边我们用长轮询来实现消息推送。

因为一个ID可能会被多个长轮询请求监听,所以我采用了guava包提供的Multimap结构存放长轮询,一个key可以对应多个value。一旦监听到key发生变化,对应的所有长轮询都会响应。前端得到非请求超时的状态码,知晓数据变更,主动查询未读消息数接口,更新页面数据。

@Controller
@RequestMapping("/polling")
public class PollingController {

    // 存放监听某个Id的长轮询集合
    // 线程同步结构
    public static Multimap<String, DeferredResult<String>> watchRequests = Multimaps.synchronizedMultimap(HashMultimap.create());

    /**
     * 公众号:程序员小富
     * 设置监听
     */
    @GetMapping(path = "watch/{id}")
    @ResponseBody
    public DeferredResult<String> watch(@PathVariable String id) {
        // 延迟对象设置超时时间
        DeferredResult<String> deferredResult = new DeferredResult<>(TIME_OUT);
        // 异步请求完成时移除 key,防止内存溢出
        deferredResult.onCompletion(() -> {
            watchRequests.remove(id, deferredResult);
        });
        // 注册长轮询请求
        watchRequests.put(id, deferredResult);
        return deferredResult;
    }

    /**
     * 公众号:程序员小富
     * 变更数据
     */
    @GetMapping(path = "publish/{id}")
    @ResponseBody
    public String publish(@PathVariable String id) {
        // 数据变更 取出监听ID的所有长轮询请求,并一一响应处理
        if (watchRequests.containsKey(id)) {
            Collection<DeferredResult<String>> deferredResults = watchRequests.get(id);
            for (DeferredResult<String> deferredResult : deferredResults) {
                deferredResult.setResult("我更新了" + new Date());
            }
        }
        return "success";
    }

当请求超过设置的超时时间,会抛出AsyncRequestTimeoutException异常,这里直接用@ControllerAdvice全局捕获统一返回即可,前端获取约定好的状态码后再次发起长轮询请求,如此往复调用。

@ControllerAdvice
public class AsyncRequestTimeoutHandler {

    @ResponseStatus(HttpStatus.NOT_MODIFIED)
    @ResponseBody
    @ExceptionHandler(AsyncRequestTimeoutException.class)
    public String asyncRequestTimeoutHandler(AsyncRequestTimeoutException e) {
        System.out.println("异步请求超时");
        return "304";
    }
}

我们来测试一下,首先页面发起长轮询请求/polling/watch/10086监听消息更变,请求被挂起,不变更数据直至超时,再次发起了长轮询请求;紧接着手动变更数据/polling/publish/10086,长轮询得到响应,前端处理业务逻辑完成后再次发起请求,如此循环往复。

长轮询相比于短轮询在性能上提升了很多,但依然会产生较多的请求,这是它的一点不完美的地方。

iframe流

iframe流就是在页面中插入一个隐藏的<iframe>标签,通过在src中请求消息数量API接口,由此在服务端和客户端之间创建一条长连接,服务端持续向iframe传输数据。

传输的数据通常是HTML、或是内嵌的javascript脚本,来达到实时更新页面的效果。

这种方式实现简单,前端只要一个<iframe>标签搞定了

<iframe src="/iframe/message" style="display:none"></iframe>

服务端直接组装html、js脚本数据向response写入就行了

@Controller
@RequestMapping("/iframe")
public class IframeController {
    @GetMapping(path = "message")
    public void message(HttpServletResponse response) throws IOException, InterruptedException {
        while (true) {
            response.setHeader("Pragma", "no-cache");
            response.setDateHeader("Expires", 0);
            response.setHeader("Cache-Control", "no-cache,no-store");
            response.setStatus(HttpServletResponse.SC_OK);
            response.getWriter().print(" <script type=\"text/javascript\">\n" +
                    "parent.document.getElementById('clock').innerHTML = \"" + count.get() + "\";" +
                    "parent.document.getElementById('count').innerHTML = \"" + count.get() + "\";" +
                    "</script>");
        }
    }
}

但我个人不推荐,因为它在浏览器上会显示请求未加载完,图标会不停旋转,简直是强迫症杀手。

SSE (我的方式)

很多人可能不知道,服务端向客户端推送消息,其实除了可以用WebSocket这种耳熟能详的机制外,还有一种服务器发送事件(Server-sent events),简称SSE

SSE它是基于HTTP协议的,我们知道一般意义上的HTTP协议是无法做到服务端主动向客户端推送消息的,但SSE是个例外,它变换了一种思路。

SSE在服务器和客户端之间打开一个单向通道,服务端响应的不再是一次性的数据包而是text/event-stream类型的数据流信息,在有数据变更时从服务器流式传输到客户端。

整体的实现思路有点类似于在线视频播放,视频流会连续不断的推送到浏览器,你也可以理解成,客户端在完成一次用时很长(网络不畅)的下载。

SSEWebSocket作用相似,都可以建立服务端与浏览器之间的通信,实现服务端向客户端推送消息,但还是有些许不同:

  • SSE 是基于HTTP协议的,它们不需要特殊的协议或服务器实现即可工作;WebSocket需单独服务器来处理协议。
  • SSE 单向通信,只能由服务端向客户端单向通信;webSocket全双工通信,即通信的双方可以同时发送和接受信息。
  • SSE 实现简单开发成本低,无需引入其他组件;WebSocket传输数据需做二次解析,开发门槛高一些。
  • SSE 默认支持断线重连;WebSocket则需要自己实现。
  • SSE 只能传送文本消息,二进制数据需要经过编码后传送;WebSocket默认支持传送二进制数据。

SSE 与 WebSocket 该如何选择?

技术并没有好坏之分,只有哪个更合适

SSE好像一直不被大家所熟知,一部分原因是出现了WebSockets,这个提供了更丰富的协议来执行双向、全双工通信。对于游戏、即时通信以及需要双向近乎实时更新的场景,拥有双向通道更具吸引力。

但是,在某些情况下,不需要从客户端发送数据。而你只需要一些服务器操作的更新。比如:站内信、未读消息数、状态更新、股票行情、监控数量等场景,SEE不管是从实现的难易和成本上都更加有优势。此外,SSE 具有WebSockets在设计上缺乏的多种功能,例如:自动重新连接事件ID发送任意事件的能力。

前端只需进行一次HTTP请求,带上唯一ID,打开事件流,监听服务端推送的事件就可以了

<script>
    let source = null;
    let userId = 7777
    if (window.EventSource) {
        // 建立连接
        source = new EventSource('http://localhost:7777/sse/sub/'+userId);
        setMessageInnerHTML("连接用户=" + userId);
        /**
         * 连接一旦建立,就会触发open事件
         * 另一种写法:source.onopen = function (event) {}
         */
        source.addEventListener('open', function (e) {
            setMessageInnerHTML("建立连接。。。");
        }, false);
        /**
         * 客户端收到服务器发来的数据
         * 另一种写法:source.onmessage = function (event) {}
         */
        source.addEventListener('message', function (e) {
            setMessageInnerHTML(e.data);
        });
    } else {
        setMessageInnerHTML("你的浏览器不支持SSE");
    }
</script>

服务端的实现更简单,创建一个SseEmitter对象放入sseEmitterMap进行管理

private static Map<String, SseEmitter> sseEmitterMap = new ConcurrentHashMap<>();

/**
 * 创建连接
 *
 * @date: 2022/7/12 14:51
 * @auther: 公众号:程序员小富
 */
public static SseEmitter connect(String userId) {
    try {
        // 设置超时时间,0表示不过期。默认30秒
        SseEmitter sseEmitter = new SseEmitter(0L);
        // 注册回调
        sseEmitter.onCompletion(completionCallBack(userId));
        sseEmitter.onError(errorCallBack(userId));
        sseEmitter.onTimeout(timeoutCallBack(userId));
        sseEmitterMap.put(userId, sseEmitter);
        count.getAndIncrement();
        return sseEmitter;
    } catch (Exception e) {
        log.info("创建新的sse连接异常,当前用户:{}", userId);
    }
    return null;
}

/**
 * 给指定用户发送消息
 *
 * @date: 2022/7/12 14:51
 * @auther: 公众号:程序员小富
 */
public static void sendMessage(String userId, String message) {

    if (sseEmitterMap.containsKey(userId)) {
        try {
            sseEmitterMap.get(userId).send(message);
        } catch (IOException e) {
            log.error("用户[{}]推送异常:{}", userId, e.getMessage());
            removeUser(userId);
        }
    }
}

我们模拟服务端推送消息,看下客户端收到了消息,和我们预期的效果一致。

注意: SSE不支持IE浏览器,对其他主流浏览器兼容性做的还不错。

MQTT

什么是 MQTT协议?

MQTT 全称(Message Queue Telemetry Transport):一种基于发布/订阅(publish/subscribe)模式的轻量级通讯协议,通过订阅相应的主题来获取消息,是物联网(Internet of Thing)中的一个标准传输协议。

该协议将消息的发布者(publisher)与订阅者(subscriber)进行分离,因此可以在不可靠的网络环境中,为远程连接的设备提供可靠的消息服务,使用方式与传统的MQ有点类似。

TCP协议位于传输层,MQTT 协议位于应用层,MQTT 协议构建于TCP/IP协议上,也就是说只要支持TCP/IP协议栈的地方,都可以使用MQTT协议。

为什么要用 MQTT协议?

MQTT协议为什么在物联网(IOT)中如此受偏爱?而不是其它协议,比如我们更为熟悉的 HTTP协议呢?

  • 首先HTTP协议它是一种同步协议,客户端请求后需要等待服务器的响应。而在物联网(IOT)环境中,设备会很受制于环境的影响,比如带宽低、网络延迟高、网络通信不稳定等,显然异步消息协议更为适合IOT应用程序。
  • HTTP是单向的,如果要获取消息客户端必须发起连接,而在物联网(IOT)应用程序中,设备或传感器往往都是客户端,这意味着它们无法被动地接收来自网络的命令。
  • 通常需要将一条命令或者消息,发送到网络上的所有设备上。HTTP要实现这样的功能不但很困难,而且成本极高。

具体的MQTT协议介绍和实践,这里我就不再赘述了,大家可以参考我之前的两篇文章,里边写的也都很详细了。

MQTT协议的介绍

我也没想到 springboot + rabbitmq 做智能家居,会这么简单

MQTT实现消息推送

未读消息(小红点),前端 与 RabbitMQ 实时消息推送实践,贼简单~

Websocket

websocket应该是大家都比较熟悉的一种实现消息推送的方式,上边我们在讲SSE的时候也和websocket进行过比较。

WebSocket是一种在TCP连接上进行全双工通信的协议,建立客户端和服务器之间的通信渠道。浏览器和服务器仅需一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。

springboot整合websocket,先引入websocket相关的工具包,和SSE相比额外的开发成本。

<!-- 引入websocket -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-websocket</artifactId>
</dependency>

服务端使用@ServerEndpoint注解标注当前类为一个websocket服务器,客户端可以通过ws://localhost:7777/webSocket/10086来连接到WebSocket服务器端。

@Component
@Slf4j
@ServerEndpoint("/websocket/{userId}")
public class WebSocketServer {
    //与某个客户端的连接会话,需要通过它来给客户端发送数据
    private Session session;
    private static final CopyOnWriteArraySet<WebSocketServer> webSockets = new CopyOnWriteArraySet<>();
    // 用来存在线连接数
    private static final Map<String, Session> sessionPool = new HashMap<String, Session>();
    /**
     * 公众号:程序员小富
     * 链接成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session, @PathParam(value = "userId") String userId) {
        try {
            this.session = session;
            webSockets.add(this);
            sessionPool.put(userId, session);
            log.info("websocket消息: 有新的连接,总数为:" + webSockets.size());
        } catch (Exception e) {
        }
    }
    /**
     * 公众号:程序员小富
     * 收到客户端消息后调用的方法
     */
    @OnMessage
    public void onMessage(String message) {
        log.info("websocket消息: 收到客户端消息:" + message);
    }
    /**
     * 公众号:程序员小富
     * 此为单点消息
     */
    public void sendOneMessage(String userId, String message) {
        Session session = sessionPool.get(userId);
        if (session != null && session.isOpen()) {
            try {
                log.info("websocket消: 单点消息:" + message);
                session.getAsyncRemote().sendText(message);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

前端初始化打开WebSocket连接,并监听连接状态,接收服务端数据或向服务端发送数据。

<script>
    var ws = new WebSocket('ws://localhost:7777/webSocket/10086');
    // 获取连接状态
    console.log('ws连接状态:' + ws.readyState);
    //监听是否连接成功
    ws.onopen = function () {
        console.log('ws连接状态:' + ws.readyState);
        //连接成功则发送一个数据
        ws.send('test1');
    }
    // 接听服务器发回的信息并处理展示
    ws.onmessage = function (data) {
        console.log('接收到来自服务器的消息:');
        console.log(data);
        //完成通信后关闭WebSocket连接
        ws.close();
    }
    // 监听连接关闭事件
    ws.onclose = function () {
        // 监听整个过程中websocket的状态
        console.log('ws连接状态:' + ws.readyState);
    }
    // 监听并处理error事件
    ws.onerror = function (error) {
        console.log(error);
    }
    function sendMessage() {
        var content = $("#message").val();
        $.ajax({
            url: '/socket/publish?userId=10086&message=' + content,
            type: 'GET',
            data: { "id": "7777", "content": content },
            success: function (data) {
                console.log(data)
            }
        })
    }
</script>

页面初始化建立websocket连接,之后就可以进行双向通信了,效果还不错

自定义推送

上边我们给我出了6种方案的原理和代码实现,但在实际业务开发过程中,不能盲目的直接拿过来用,还是要结合自身系统业务的特点和实际场景来选择合适的方案。

推送最直接的方式就是使用第三推送平台,毕竟钱能解决的需求都不是问题,无需复杂的开发运维,直接可以使用,省时、省力、省心,像goEasy、极光推送都是很不错的三方服务商。

一般大型公司都有自研的消息推送平台,像我们本次实现的web站内信只是平台上的一个触点而已,短信、邮件、微信公众号、小程序凡是可以触达到用户的渠道都可以接入进来。

消息推送系统内部是相当复杂的,诸如消息内容的维护审核、圈定推送人群、触达过滤拦截(推送的规则频次、时段、数量、黑白名单、关键词等等)、推送失败补偿非常多的模块,技术上涉及到大数据量、高并发的场景也很多。所以我们今天的实现方式在这个庞大的系统面前只是小打小闹。

Github地址

文中所提到的案例我都一一的做了实现,整理放在了Github上,觉得有用就 Star 一下吧!

传送门:https://github.com/chengxy-nds/Springboot-Notebook/tree/master/springboot-realtime-data


redislog

0311lc.com说:
<?php
require("redis.php");
$l = $redis->get("userid");

$count = $redis->lLen("uid");//总数 添加中脸链表关键词uid

$page_size = 3;//页大小
$page_num = (!empty($_GET['page'])) ? $_GET['page'] : 1;//当前页
$page_count = ceil($count/$page_size);//页总数
// add.php 形成链表
//用 lrange查看分页 lrange uid 0  2  第一页  lrange uid 3  5  第二页  lrange uid 6  8

$uid_lstart = ($page_num -1 ) * $page_size;
$uid_lend = $uid_lstart +  ($page_size -1);
$ids = $redis->lRange("uid",$uid_lstart,$uid_lend);

//1.这款的数组=============$ids改写为sort排序=================================
$sort_dispaly_hash_key = 'user';
$sort_dispaly_f = array('uid','username','age');
$sort_pai = 'desc';
$sort_by = 'user:*->uid';

$sort_farr = array();
foreach ($sort_dispaly_f as $index => $item) {
    $sort_farr[] = $sort_dispaly_hash_key.':*->'.$item;
}
$sort_farrl = count($sort_dispaly_f);
$sort=array(
    'BY'=>$sort_by,
    'SORT'=>$sort_pai,
    'limit'=>array($uid_lstart,$page_size),
    'GET'=>$sort_farr
);
$rs_sort= $redis->sort('uid',$sort);
$rs_sort_new = [];
if(!empty($rs_sort)){


    foreach ($rs_sort as $index => $item) {
        if($index % $sort_farrl == 0){
            $insert_f = array();
            foreach ($sort_dispaly_f as $kk => $sort_dispaly_f_v) {

                $index_k = ($kk == 0) ? $index : $index+$kk;
                $insert_f[$sort_dispaly_f_v] =  $rs_sort[$index_k];
            }
            $rs_sort_new[] = $insert_f;
        }
    }
}


/**
无分页的列表
for($i=1;$i<=$l ;$i++){

    $data[] = $redis->hgetall("user:".$i);
}
//$data = array_filter($data);
**/

/**
 * 有分页的列表
 *  list.php?page=1
 * list.php?page=2
 * list.php?page=3
 */
//print_r($ids); //测试没问题
foreach ($ids as $v){
    $data[] = $redis->hgetall("user:".$v);
}
$data = $rs_sort_new;
?>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">


<?php

    $login_uname = "";
    if(!empty($_COOKIE['token'])){
       $login_uid =  $redis->get("token:".$_COOKIE['token']);
       $login_uname = $redis->hGet("user:".$login_uid,"username");
       echo "<a href=\"add.php\">添加</a>";
       echo "欢迎您,{$login_uname} <a href=\"logout.php\" >退出</a>";
    }else{
       echo "<a href=\"login.php\" >登录</a>  | ";

        echo " <a href=\"reg.php\" >注册</a>";
    }
?>

<br />============================================<br />
<table border="1">
    <tr>
        <th>id</th>
        <th>姓名</th>
        <!--<th>密码</th>-->
        <th>年龄</th>
        <th>操作</th>
    </tr>
    <?php
    foreach ($data as $index => $v) {
    ?>
    <tr>
        <td><?php  echo $v['uid'];?></td>
            <td><?php  echo $v['username'];?></td>
            <!--<td><?php  echo $v['password'];?></td>-->
            <td><?php  echo $v['age'];?></td>
            <td>
                <?php
                if(!empty($_COOKIE['token'])) {
                ?>
                    <a href="del.php?id=<?php echo $v['uid'];?>">删除</a>
                    <a href="mod.php?id=<?php echo $v['uid'];?>">编辑</a>
                    <?php
                    if($login_uid !== $v['uid'] ){
                        ?>
                        <a href="addfans.php?id=<?php echo $v['uid']?>&login_uid=<?php echo $login_uid ?>" />加关注</a>
                        <?php
                    }
                    ?>
                <?php
                }
                ?>

            </td>

    </tr>
        <?php
    }
    ?>
    <tr>
        <td colspan="4">
            <a href="?page=<?php echo  (($page_num - 1) <= 1 ) ? 1 : ($page_num - 1) ?>">上一页</a>
            <a href="?page=<?php echo (($page_num + 1) >= $page_count ) ? $page_count : ($page_num + 1) ?>">下一页</a>
            <a href="?page=1">首页</a>
            <a href="?page=<?php echo $page_count ?>">尾页</a>
            当前 <?php echo $page_num ?> 页
            总共 <?php echo $page_count ?>页
            总共  <?php echo $count ?> 个用户
        </td>
    </tr>
</talbe>
    <br />

 <table border="1">
     <tr>
    <td colspan="4">我关注了谁(<?php echo $redis->sCard("user:".$login_uid.":guanzhu"); ?>)</td>
     </tr>
     <?php

        $rs_guanzhu = $redis->sMembers("user:".$login_uid.":guanzhu");

        foreach ( $rs_guanzhu as $index => $item) {
            $row = $redis->hGetAll("user:".$item)

     ?>
     <tr>
         <td><?php echo $row['uid'] ?> </td>
         <td><?php echo $row['username'] ?></td>
         <td><?php echo $row['age'] ?></td>
         <td>
             <?php
                $rs_gongtong = $redis->sInter("user:".$login_uid.":guanzhu","user:".$item.":guanzhu");
                if (!empty($rs_gongtong)){
                    echo "共同关注了:";
                    foreach ($rs_gongtong as $fff=> $gv){
                        $row_gv = $redis->hGetAll("user:".$gv);
                        echo $row_gv['username'].',';

                    }
                }
             ?>
         </td>

     </tr>
     <?php
        }
     ?>
 </table>

<table border="1">
    <tr>
        <td colspan="4">我的粉丝,谁关注我(<?php echo $redis->sCard("user:".$login_uid.":fensi"); ?>)</td>
    </tr>
    <?php
    $rs_fensi = $redis->sMembers("user:".$login_uid.":fensi");

    foreach ( $rs_fensi as $index => $item) {
        $row = $redis->hGetAll("user:".$item)
        ?>
        <tr>
            <td><?php echo $row['uid'] ?> </td>
            <td><?php echo $row['username'] ?></td>
            <td><?php echo $row['age'] ?></td>
            <td>
                <?php
                //互粉是好友
                $login_is_u_g = $redis->sIsMember("user:".$item.":guanzhu",$login_uid);
                $u_is_login_g = $redis->sIsMember("user:".$login_uid.":guanzhu",$item);

                if ($login_is_u_g && $u_is_login_g)
                {
                    echo "是好友";
                }
                ?>

            </td>
        </tr>
        <?php
    }
    ?>
</table>
 <table border="1">
     <tr>
         <td colspan="3">是好友的-互为关注  sInter fensi guanzhu </td>
     </tr>
     <?php
     $rs_fensi = $redis->sInter("user:".$login_uid.":fensi","user:".$login_uid.":guanzhu");

     foreach ( $rs_fensi as $index => $item) {
         $row = $redis->hGetAll("user:".$item)
         ?>
         <tr>
             <td><?php echo $row['uid'] ?> </td>
             <td><?php echo $row['username'] ?></td>
             <td><?php echo $row['age'] ?></td>

         </tr>
         <?php
     }
     ?>
    </table>
    <br />
    redis key的个数:<?php echo $redis_db_count = $redis->dbSize(); ?><br />
    redis 信息:<?php $redis_info= $redis->info(); ?><br />
    redis版本:<?php echo $redis_info['redis_version'];?><br />
    <div style="display: none">
    <pre>
        <?php print_r($redis_info); ?>
    </pre>
    </div>
    ========================redis源码包git信息==================<br />
    redis_git_sha1:<?php echo $redis_info['redis_git_sha1'];?><br />
    redis_git_dirty:<?php echo $redis_info['redis_git_dirty'];?><br />
    redis_build_id:<?php echo $redis_info['redis_build_id'];?><br />
    redis_mode:<?php
    $redis_mode_arr = ["standalone"=>"独立","cluster"=>"集群"];
    echo  $redis_mode_arr[$redis_info['redis_mode']];
    ?><br />内存碎片率
    当前连接数:<?php echo $redis_info['connected_clients'];?><br />
    已使用内存: <?php echo $redis_info['used_memory'];?>|<?php echo $redis_info['used_memory_human'];?><br />
    Redis占用的物理内存: <?php echo $redis_info['used_memory_rss'];?>|<?php echo $redis_info['used_memory_rss_human'];?><br />
    Redis的内存使用峰值: <?php echo $redis_info['used_memory_peak'];?>|<?php echo $redis_info['used_memory_peak_human'];?><br />
    所在服务器系统总内存: <?php echo $redis_info['total_system_memory'];?>|<?php echo $redis_info['total_system_memory_human'];?><br />
    lua使用的内存: <?php echo $redis_info['used_memory_lua'];?>|<?php echo $redis_info['used_memory_lua_human'];?><br />
    最大使用内存限制: <?php echo $redis_info['maxmemory'];?>|<?php echo $redis_info['maxmemory_human'];?><span style="color:#cccccc;font-size: 11px">(最大使用内存限制,超过时,会使用LRU或LFU策略删除key,该值尽量设置的小于系统内存[maxmemory])</span><br />
    内存碎片率: <?php echo $redis_info['mem_fragmentation_ratio'];?><span style="color:#cccccc;font-size: 11px">(used_memory_rss / used_memory内存碎片率,过高对性能的影响)</span><br />
    内存分配器: <?php echo $redis_info['mem_allocator'];?><br />
    =========================Persistence RDB和AOF相关信息================<br />
    loading:<?php echo $redis_info['loading']; ?> 是否有加载转储文件的标识,0=无,1=有,内存耗尽可能会有<br />
    最后一次保存时间戳:<?php echo $redis_info['rdb_last_save_time']; ?> |  <?php echo date("Y-m-d H:i:s",$redis_info['rdb_last_save_time']) ; ?><br />
    =========================数据库中的key总量,过期key总量,平均过期时长(毫秒)=================== <br />
    <?php

    for ($i=0;$i<=16;$i++){
        if(!empty($redis_info['db'.$i])){
            echo  'db'.$i.': ======'.$redis_info['db'.$i].'<br />';
        }
    }
    ?>
    =====================================================================<br />
    <pre>
<?php
$redis_key = $redis->keys("*");
//window 是这样  liunx 返回其他
$rs_type_arr = [ '不存在','字符串','集合','列表','有序集合','哈希表'];
$redis_key_new = [];
if(!empty($redis_key)){
    foreach ($redis_key as  $item) {
        //echo $item.'=>' .$rs_type_arr[$redis->type($item)]."<br />";
        $redis_key_new[$rs_type_arr[$redis->type($item)]][] = $item;
    }
}
if (!empty($redis_key_new)){
    $hx_arr = $str_arr = $ls_arr= $yxjh_arr = $wxjh_arr = [];
    foreach ($redis_key_new as $index=> $item) {
        if ($index == '哈希表'){
            $hx_arr = $item;
        }
        if ($index == '字符串'){
            $str_arr = $item ;
        }
        if ($index == '列表'){
            $ls_arr = $item ;
        }
        if ($index == '有序集合'){
            $yxjh_arr = $item ;
        }
        if ($index == '集合'){
            $wxjh_arr = $item ;
        }
    }
}
if(!empty($str_arr))
{
    $str_arr_new = [];
    foreach ($str_arr as $index => $item) {
        $str_arr_new[$item] = $redis->Get($item);
    }
    echo "=======================================string=============================<br />";
    print_r($str_arr_new);
}
if(!empty($ls_arr))
{
    $ls_arr_new = [];
    foreach ($ls_arr as $index => $item) {
        $ls_arr_new[$item] = $redis->lrange($item, 0 , -1);

    }
    echo "======================================list==================================<br />";
    print_r($ls_arr_new);
}
if(!empty($hx_arr)){
    $hx_arr_new = [];
    foreach ($hx_arr as $index => $item) {
        $hx_arr_new[$item] = $redis->hGetAll($item);
    }
    echo "======================================hash===================================<br />";
    print_r($hx_arr_new);
}

if(!empty($wxjh_arr)){

    $wxjh_arr_new = [];
    foreach ($wxjh_arr as $index => $item) {

        $wxjh_arr_new[$item] = $redis->sMembers($item);
    }
    echo "======================================set集合===================================<br />";
    print_r($wxjh_arr_new);
}
?>
    </pre>

 


php扩展 通用 – compser安装

0311lc.com说:
扩展 通用
 tar -zxvf yac-2.3.1.tgz
cd yac-2.3.1
/usr/local/php/bin/phpize
./configure –with-php-config=/usr/local/php/bin/php-config
make && make install
ls /usr/local/php/lib/php/extensions/no-debug-non-zts-20190902/
打开 php  的 php.ini 放入扩展 ***.so
 /etc/init.d/php-fpm restart

========================================
compser
mv composer.phar /usr/local/bin/composer
composer -v
composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/
composer config -l -g
==============================

phpstudy thinkphp6

0311lc.com说:

window10 下 phpstudy2018

nginx  模式下 配置

是双杠

root “G:\\myapp\\tp\\public”;

 

完整

server {
listen 80;
server_name myapp.cc ;
root “G:\\myapp\\tp\\public”;
index index.php index.html index.htm;
location / {
#autoindex on;
if (!-e $request_filename) {
rewrite ^/(.*)$ /index.php/$1 last;
break;
}
}

location ~ \.php(.*)$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_split_path_info ^((?U).+\.php)(/?.+)$;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;
include fastcgi_params;
}
}


compser phpstudy

0311lc.com说:
查看composer版本
1.查询位置在compser安装目录下执行
E:phpstudy_proExtensionsphpphp7.1.9ntsphp.exe composer.phar -V 显示版本号则为正常

2.composer默认是国外的镜像,如果想使用国内镜像 https://packagist.phpcomposer.com 还需要配置一下E:phpstudy_proExtensionsphpphp7.1.9ntsphp.exe composer.phar config -g repo.packagist composer httpp://packagist.phpcomposer.com

 

 

https://packagist.phpcomposer.com
快速设置windows 国内镜像

在windows 黑窗口 操作 > composer config -g repo.packagist composer https://packagist.phpcomposer.com

composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/

查看全局配置:

composer config -l -g

 

安装laravel v6.18.3版本 composer create-project laravel/laravel laravel6.8 v6.18.3

 

 

===================================================

出现的错误:
[InvalidArgumentException]
Could not find package topthink/think with stability stable.

解决方案:
删除之前的镜像:composer config -g –unset repos.packagist


php面试

0311lc.com说:
1:变量的传值与引用。
2:变量的类型转换和判断类型方法。
3:php运算符优先级,一般是写出运算符的运算结果。
4:PHP中函数传参,闭包,判断输出的echo,print是不是函数等。
5:PHP数组,数组函数,数组遍历,预定义数组(面试必出)。
6:PHP面向对象,魔术方法,封装、继承、多态。设计模式,包括(单利、工厂、迭代器、装饰、命令、策略)。
7:正则表达式,每个标号含义,邮箱、网址、标签匹配,正则函数(面试必出)。
8:PHP异常处理(级别,错误日志,控制错误输出)。
9:PHP时间函数,日期计算函数。
10:文件系统,记录日志、目录、文件的遍历、上传、多方法得到文件扩展名、文件引用方式、引用函数区别。(面试必出)。
11:会话控制,主要说原理。session与cookie在分布式应用中出现问题的解决方案。
12:PHP模板引擎,常用模板引擎特点,MVC好与不好的地方。
13:PHP安全处理,过滤函数。
14:XML的使用。
15:PHP字符串的处理,包括转义(安全)、编码、截取、定位、与数组间的转换、处理函数等。(面试必出)。
16:Socket编程,各种协议,head头,curl参数含义。
17:网络状态码含义,常用(204,304, 404, 504,502)。
18:Apache配置文件,PHP配置文件,各个含义字段的含义。
19:网络各种攻击的名词含义(SQL攻击、XSS、CSRF、DDos),防止措施。
20:url的处理函数,得到url指定的部分。
1:基础sql语句书写(一般让写关联和子查询语句)
2:索引的创建,优缺点,最左原则
3:存储引擎,常用的几个,优缺点,差别,原理(面试必出)
4:sql注入的处理方法
5:mysql处理函数(PHP中封装的)
6:PDO的使用方法,为什么使用
7:mysql的优化,表拆分等
8:事务处理,sql语句的处理效率等
9:数据表字段的类型,同类型间的区别,改如何选取,int(10)与int(11)的区别等。
10:数据库索引使用的那种数据结构,画出数据结构
1:常用命令的使用,vim编辑器的使用。
2:进程,cpu等信息的查看命令。
3:文件内查看命令(主要涉及统计信息)。
4:Shell的使用,命令操作。
1:Redis的应用场景,结合微博业务说出他的具体应用。
2:Redis与MC支持数据的不同点,两者都支持哪些数据结构的存储,写越多越好。
3:Redis持久化存储的原理,与Mysql的应用区别。怎样保持持久化数据与内存数据同步的关系(Redis同步机制)
4:Redis与MC在并发状态下的性能比较。
5:MC的内存管理机制,当一个数据需要存储的时候怎样分配内存空间
6:Redis的内存管理机制,与MC有哪些不同点。
1:PHP7中的新特性与废弃的特性
2:为什么要使用PHP7,PHP7快在哪里
1:git的使用命令,例如:写出版本回退命令。
2:git与svn的区别。
3:如何进行多分支开发,包括多人开发协同,分段测试,上线。

1、HTTP Keep-Alive的作用

作用:Keep-Alive:使客户端到服务器端的连接持续有效,当出现对服务器的后继请求时,Keep-Alive功能避免了建立或者重新建立连接。Web服务器,基本上都支持HTTP Keep-Alive。

缺点:对于提供静态内容的网站来说,这个功能通常很有用。但是,对于负担较重的网站来说,虽然为客户保留打开的连 接有一定的好处,但它同样影响了性能,因为在处理暂停期间,本来可以释放的资源仍旧被占用。当Web服务器和应用服务器在同一台机器上运行时,Keep- Alive功能对资源利用的影响尤其突出。

解决:Keep-Alive: timeout=5, max=100
timeout:过期时间5秒(对应httpd.conf里的参数是:KeepAliveTimeout),max是最多一百次请求,强制断掉连接。就是在timeout时间内又有新的连接过来,同时max会自动减1,直到为0,强制断掉。

数组相关———-|

1、php数组函数常见的那些? (array_merge、in_array的作用)
2、PHP中以array_开头的数组函数有哪些,并说出使用方法(至少6个)
数组操作的基本函数
1 array_values($arr);       //获得数组的值
2 array_keys($arr);         //获得数组的键名
3 array_flip($arr);         //数组中的值与键名互换(如果有重复前面的会被后面的覆盖)
4 array_search('PHP',$arr); //检索给定的值,加true则是严格类型检查
5 array_reverse($arr);      //将数组中的元素翻转
6 in_array("apple", $arr);  //在数组中检索apple
7 array_key_exists("apple", $arr); // 检索给定的键名是否存在数组中
8 array_count_values($arr);        // 统计数组中所有值出现的次数

数组的分段和填充

1 array_slice($arr, 0, 3);    //将数组中的一段取出,此函数忽略键名(数组的分段)
2 array_splice($arr, 0, 3,array("black","maroon"));    //将数组中的一段取出,返回的序列从原数组中删除
3 array_chunk($arr, 3, TRUE);   //将一个数组分割成多个,TRUE为保留原数组的键名(分割多个数组)

数组与栈,列队

1 array_push($arr, "apple", "pear");    //将一个或多个元素压入数组栈的末尾(入栈),返回入栈元素的个数
2 array_pop($arr);    // 将数组栈的最后一个元素弹出(出栈)
3 array_shift($arr);   //数组中第一个元素移出并返回(长度减1,其他元素向前移动一位,数字键名改为从零计数,文字键名不变)
4 array_unshift($arr,"a",array(1,2));  //在数组的开头插入一个或多个元素

数组的排序

1 sort($arr);       //由小到大,忽略键名       
2 rsort($arr);      //由大到小,忽略键名
3 asort($arr);     //由小到大,保留键名       
4 arsort($arr);    // 由大到小,保留键名
5 ksort($arr);     //按照键名正序排序           
6 krsort($arr);   // 按照键名逆序排序

数组的计算

1 array_sum($arr);   //对数组内部的所有元素做求和运算(数组元素的求和)
2 array_merge($arr1, $arr2); //合并两个或多个(相同字符串键名,后面覆盖前面,相同的数字键名,后面的附加到后面)
4 array_diff($arr1, $arr2);           //返回差集结果数组   array_diff_assoc($arr1, $arr2, $arr3);  //返回差集结果数组,键名也做比较
5 array_intersect($arr1, $arr2);  //返回交集结果数组    array_intersect_assoc($arr1, $arr2);   //返回交集结果数组,键名也做比较

其他的数组函数

1 array_unique($arr);   //移除数组中重复的值,新的数组中会保留原始的键名
2 shuffle($arr);             // 将数组的顺序打乱
PHP中几个输出函数echo,print(),print_r(),sprintf(),var_dump()的区别

1:echo:是语句不是函数,没有返回值,可输出多个变量值,不需要圆括号。不能输出数组和对象,只能打印简单类型(如int,string)。

2:print:是语句不是函数,有返回值 1 ,只能输出一个变量,不需要圆括号。不能输出数组和对象,只能打印简单类型(如int,string)。

3:print_r:是函数,可以打印复合类型,例如:stirng、int、float、array、object等,输出array时会用结构表示,而且可以通过print_r($str,true)来使print_r不输出而返回print_r处理后的值

4:printf:是函数,把文字格式化以后输出(参看C语言)

5:sprintf:是函数,跟printf相似,但不打印,而是返回格式化后的文字(该函数把格式化的字符串写写入一个变量中,而不是输出来),其    他的与printf一样。

6:var_dump():函数,输出变量的内容、类型或字符串的内容、类型、长度。常用来调试。

可以通过function_exists('函数名称')进行测试

不用新变量直接交换现有两个变量的值

 
 3     list($a, $b) = array($b, $a);
 4 2:  5     $a = $a . $b;
 5     $b = strlen( $b );
 6     $b = substr( $a, 0, (strlen($a) – $b ) );
 7     $a = substr( $a, strlen($b) );
 8 
 9 3:(必须用一个两个字符串都都不能出现的字符做为分隔符)
10     $a = $b.','.$a ;
11     $a = explode(',', $a);
12     $b = $a[1];
13     $a = $a[0];
14 
15 4:这个是当两个数都是数字的时候:
16     $a = $a + $b;
17     $b = $a – $b;
18     $a = $a – $b;
19 
20 5:借助数组
21     $a = array($a,$b);
22     $b = $a[0];
23     $a = $a[1];

heredoc

Heredoc在正规的PHP文档中和技术书籍中一般没有详细讲述。他是一种Perl风格的字符串输出技术。使用heredoc技术可以实现界面与代码的准分离,比如phpwind模板。

heredoc的语法是用”<<<”加上自己定义成对的标签,在标签范围內的文字视为一个字符串

规则如下:

1、以<<<End开始标记开始,以End结束标记结束,结束标记必须顶头写,不能有缩进和空格,且在结束标记末尾要有分号 。开始标记和开始标记相同,比如常用大写的EOT、EOD、EOF来表示,也可以使用其他标记,只要保证开始标记和结束标记不在正文中出现就行

2、位于开始标记和结束标记之间的变量可以被正常解析,但是函数则不可以。在heredoc中,变量不需要用连接符 . 或 , 来拼接,比如:

1 $a=2;
2 $b= <<<EOF
3 "zyf"$a
4 "zyf"
5 EOF;
6 echo $b; //结果连同双引号一起输出:"zyf"2 "zyf"

3、heredoc常用在输出包含大量HTML语法文档的时候。他要比传统的echo输出精炼很多,如下所示:

 1 function getHtml()
 2 {
 3     echo "<html>";
 4     echo "<head><title>Title</title></head>";
 5     echo "<body>Content</body>";
 6     echo "</html>;
 7 }
 8 
 9 function getHtml()
10 {
11 echo <<<EOT
12       <html>
13       <head><title>Title</title></head>
14       <body>Content</body>
15       </html>
16 EOT;
17 }

写个函数来解决多线程同时读写一个文件的问题。

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

禁掉cookie的session使用方案,设置session过期的方法,对应函数:

通过 url 传值,把session id附加到url上(缺点:整个站点中不能有纯静态页面,因为纯静态页面session id 将无法继续传到下一页面)
通过隐藏表单,把session id 放到表单的隐藏文本框中同表单一块提交过去(缺点:不适用<a>标签这种直接跳转的非表单的情况)
直接配置php.ini文件,将php.ini文件里的session.use_trans_sid= 0设为1,(好像在win上不支持)
用文件、数据库等形式保存Session ID,在跨页过程中手动调用
1 第一种  setcookie() 直接用setcookie设置session id的生命周期。
 3     $lifetime=60; //保存1分钟 
 4     session_start(); 
 5     setcookie(session_name(), session_id(), time()+$lifetime, "/");
 6 第二种  session_set_cookie_params()    
 7     $lifetime=60;//保存1分钟
 8     session_set_cookie_params($lifetime);
 9     session_start();
10     session_regenerate_id(true);
11     其中session_regenerate_id();方法用于改变当前session_id的值,并保留session中数组的值。参数默认为 false,如果设置为true则改变session_id的值,并清空当前session数组。
php获取文件内容的方法,对应的函数
1:file_get_contents得到文件的内容(可以以get和post的方式获取),整个文件读入一个字符串中
2:用fopen打开url, 以get方式获取内容(借助fgets()函数)
3:用fsockopen函数打开url(可以以get和post的方式获取),以get方式获取完整的数据,包括header和body
4:使用curl库获取内容,使用curl库之前,需要查看php.ini,查看是否已经打开了curl扩展
 
php魔术方法与魔术常量
方法:__construct(),__destruct()。    
方法重载:__call(),__callStatic()。
属性重载:__get(),__set(),__isset(),__unset()  //这四个只对类中私有受保护的成员属性有效
__toString(),__autoload();
_set_state(); //自 PHP 5.1.0 起当调用 var_export() 导出类时,此静态 方法会被调用。 本方法的唯一参数是一个数组。
 
__clone();       //通常用于对副本进行重新初始化,
说明:this指副本对象引用,that指原对象引用 等方法在 PHP 中被称为”魔术方法”。PHP 将所有以 __(两个下划线)开头的类方法保留为魔术方法。所以在定义类方法时,除了上述魔术方法,建议不要以 __ 为前缀。在命名自己的类方法时不能使用这些方法名,除非是想使用其魔术功能。
 
常量:
__LINK__      //文件中的当前行号。
__FILE__       //文件的完整路径和文件名。如果用在被包含文件中,则返回被包含的文件名。
__DIR__       //文件所在的目录。如果用在被包括文件中,则返回被包括的文件所在的目录,它等价于 dirname(__FILE__)。
 
__FUNCTION__       //函数名称。自 PHP 5 起本常量返回该函数被定义时的名字(区分大小写)。在 PHP 4 中该值总是小写字母的。
 __CLASS__              //类的名称。自 PHP 5 起本常量返回该类被定义时的名字(区分大小写)。在 PHP 4 中该值总是小写字母的。
 __METHOD__         //类的方法名(PHP 5.0.0 新加)。返回该方法被定义时的名字(区分大小写)。
 __NAMESPACE__   //当前命名空间的名称(大小写敏感)。这个常量是在编译时定义的(PHP 5.3.0 新增)
 
PHP 如何获取客户端的IP地址,

用$_SERVER获取的IP地址有什么问题?

$_SERVER['REMOTE_ADDR'] ;   通过全局数组来获得 

getenv('REMOTE_ADDR') ; 通过环境变量来获得

当客户机使用代理的时候获取不到真实的IP地址

写一个函数,可以遍历文件夹下的所有文件和文件夹。

function get_dir_info($path){
          $handle = opendir($path);//打开目录返回句柄
          while(($content = readdir($handle))!== false){
                $new_dir = $path . DIRECTORY_SEPARATOR . $content;
                if($content == '..' || $content == '.'){
                       continue;
                }
                if(is_dir($new_dir)){
                      echo "<br>目录:".$new_dir . '<br>';
                      get_dir_info($new_dir);
                }else{
                      echo "文件:".$path.':'.$content .'<br>';
                }
          }
      }
      get_dir_info($dir);

有mail.log的一个文档,内容为若干邮件地址,用’\n’分隔换行。挑选sina.com的地址(包括从文件读取、过滤到列印出来)。

思路1:用正则表达式(比较慢,效率地,不推荐用)

思路2:cat mail.log | grep sina.com

 

PHP缓存技术有哪些? tp是局部还是完全缓存?

1. 全页面静态化缓存,也就是将页面全部生成html静态页面,用户访问时直接访问的静态页面,而不会去走php服务器解析的流程
2. 页面部分缓存,将一个页面中不经常变的部分进行静态缓存,而经常变化的块不缓存,最后组装在一起显示
3. 数据缓存,通过一个id进行请求的数据,将数据缓存到一个php文件中,id和文件是对应的,下次通过这个id进行请求时 直接读php文件
4. 查询缓存,和数据缓存差不多,根据查询语句进行缓存;
5. 常用的缓存技术有:redis和memcache
个人认为tp应该是全局缓存 因为:tp缓存实在本地生成一个php文件来存储数据库中读取出来的数据

strlen()与mb_strlen的作用与区别

在PHP中,strlen与mb_strlen是求字符串长度的函数

PHP内置的字符串长度函数strlen无法正确处理中文字符串,它得到的只是字符串所占的字节数。对于GB2312的中文编码,strlen得到的值是汉字个数的2倍,而对于UTF-8编码的中文,就是3倍(在 UTF-8编码下,一个汉字占3个字节)。

采用mb_strlen函数可以较好地解决这个问题。mb_strlen的用法和strlen类似,只不过它有第二个可选参数用于指定字符编码。例如得到UTF-8的字符串$str长度,可以用 mb_strlen($str,’UTF-8′)。如果省略第二个参数,则会使用PHP的内部编码。内部编码可以通过 mb_internal_encoding()函数得到。

需要注意的是,mb_strlen并不是PHP核心函数,使用前需要确保在php.ini中加载了php_mbstring.dll,即确保“extension=php_mbstring.dll”这一行存在并且没有被注释掉,否则会出现未定义函 数的问题。
写一个函数,尽可能高效的从一个标准url中取出扩展名

$arr = parse_url(‘http://www.sina.com.cn/abc/de/fg.php?id=1’);

$result = pathinfo($arr[‘path’]);var_dump($arr);
var_dump($result[‘extension’]);

php.ini 中safe mod关闭 影响哪些函数和参数,至少写6个?

move_uploaded_file()        exec()
system()                              passthru()
popen()                              fopen()
mkdir()                               rmdir()
rename()                            unlink()
copy()                                 chgrp()
chown()                              chmod()
touch()                               symlink()
link()                                   parse_ini_file()
set_time_limit()                  max_execution_time mail()

 

一群猴子排成一圈,按1,2,…,n依次编号。然后从第1只开始数,数到第m只,把它踢出圈,从它后面再开始数,再数到第m只,在把它踢出去…,如此不停 的进行下去,直到最后只剩下一只猴子为止,那只猴子就叫做大王。要求编程模拟此过程,输入m、n, 输出最后那个大王的编号。

<?php
 function fuhuan($allnum, $ti){
     $arr = array();
     for($i = 0; $i < $allnum; $i++){
         $arr[$i] = $i;
     }

     $nums = 1;
     while(count($arr) > 1){
          foreach ($arr as $key => $value) {
              if($nums == $ti){
                  unset($arr[$key]);
                  $nums = 1;
              }else{
                  $nums++;
              }
         }
     }
     $new_arr = array_values($arr);
     var_dump($new_arr[0] + 1);
 }
 fuhuan(10,10);

isset() 、empty()与is_null的区别

1、当变量未定义时,is_null() 和“参数本身”是不允许作为参数判断的,会报Notice警告错误;

2、empty , isset首先都会检查变量是否存在,然后对变量值进行检测。而is_null 和 “参数本身”只是直接检查变量值,是否为null,因此如果变量未定义就会出现错误!

3、isset():仅当null和未定义,返回false;

4、empty():””、0、”0″、NULL、FALSE、array(),未定义,均返回true;

5、is_null():仅判断是否为null,未定义报警告;

6、变量本身作为参数,与empty()一致,但接受未定义变量时,报警告;

求两个文件的相对路径

getpath('/a/b/c/d/e.php', '/a/d/12/34/c.php');

public function getpath($a, $b)
{
     $aarr = explode('/', $a);
     $barr = explode('/', $b);
     $count = count($barr) - 2;
     $pathinfo = '';
     for($i = 1; $i <= $count; $i++){
         if($aarr[$i] == $barr[$i]){
              $pathinfo .= '../';
         }else{
              $pathinfo .= $barr[$i] . '/';
         }
     }
     echo $pathinfo;
}
MVC的优缺点
1、 MVC的优点 
        (1) 可以为一个模型在运行时同时建立和使用多个视图。变化-传播机制可以确保所有相关的视图及时得到模型数据变化,从而使所有关联的视图和控制器做到行为同步。 
        (2) 视图与控制器的可接插性,允许更换视图和控制器对象,而且可以根据需求动态的打开或关闭、甚至在运行期间进行对象替换。 
        (3) 模型的可移植性。因为模型是独立于视图的,所以可以把一个模型独立地移植到新的平台工作。需要做的只是在新平台上对视图和控制器进行新的修改。 
        (4) 潜在的框架结构。可以基于此模型建立应用程序框架,不仅仅是用在设计界面的设计中。 
2、 MVC的不足之处 
        (1) 增加了系统结构和实现的复杂性。对于简单的界面,严格遵循MVC,使模型、视图与控制器分离,会增加结构的复杂性,并可能产生过多的更新操作,降低运行效率。 
        (2) 视图与控制器间的过于紧密的连接。视图与控制器是相互分离,但确实联系紧密的部件,视图没有控制器的存在,其应用是很有限的,反之亦然,这样就妨碍了他们的独立重用。 
        (3) 视图对模型数据的低效率访问。依据模型操作接口的不同,视图可能需要多次调用才能获得足够的显示数据。对未变化数据的不必要的频繁访问,也将损害操作性能。 
        (4) 目前,一般高级的界面工具或构造器不支持MVC模式。改造这些工具以适应MVC需要和建立分离的部件的代价是很高的,从而造成使用MVC的困难。 
 
 
session与cookie的联系和区别(运行机制),session共享问题解决方案:
区别与联系:
    使用session_start()调用session,服务器端在生成session文件的同时生成session ID哈希值和默认值为PHPSESSID的session name,并向客户端发送变量为PHPSESSID(session name)(默认)值为一个128位的哈希值。服务器端将通过该cookie与客户端进行交互,session变量的值经php内部系列化后保存在服务器 机器上的文本文件中,和客户端的变量名默认情况下为PHPSESSID的coolie进行对应交互,即服务器自动发送了http 头:header(‘Set-Cookie: session_name()=session_id(); path=/’);即setcookie(session_name(),session_id());当从该页跳转到的新页面并调用 session_start()后,PHP将检查与给定ID相关联的服务器端存贮的session数据,如果没找到则新建一个数据集。
共享方案:
1:使用数据库保存session, 使用数据库来保存session,就算服务器宕机了也没事,session照样在。
问题:程序需要定制;每次请求都进行数据库读写开销不小,另外数据库是一个单点,可以做数据库的hash来解 决这个问题。       

2:使用 memcached来保存session, 这种方式跟数据库类似,内存存取性能比数据库好很多。

问题:程序需要定制,增加 了工作量;存入memcached中的数据都需要序列化,效率较低,断电或者重启电脑容易丢失数据;

3: 通过加密的cookie,在A服务器上登录,在用户的浏览器上添加加密的cookie,当用户访问B服务器时,检查有无Session,如果没有,就检验 Cookie是否有效,Cookie有效的话就在B服务器上重建session。简单,高效, 服务器的压力减小了,因为session数据不存在服务器磁盘上。根本就不会出现session读取不到的问题。

问题:网络请求占用很多。每次请求时,客户端都要通过cookie发送session数据给服务器,session中数据不能太多,浏览器对cookie 的大

小存在限制。不适合高访问量的情况,因为高访问量的情况下。

 

 正则表达式

匹配中文字符的正则表达式: [\u4e00-\u9fa5] 
匹配双字节字符(包括汉字在内):[^\x00-\xff] 
匹配空行的正则表达式:\n[\s| ]*\r 
匹配HTML标记的正则表达式:/<(.*)>.*<\/\1>|<(.*) \/>/ 
匹配首尾空格的正则表达式:(^\s*)|(\s*$) 
匹配Email地址的正则表达式:\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)* 
匹配网址URL的正则表达式:^[a-zA-z]+://(\\w+(-\\w+)*)(\\.(\\w+(-\\w+)*))*(\\?\\S*)?$ 
匹配帐号是否合法(字母开头,允许5-16字节,允许字母数字下划线):^[a-zA-Z][a-zA-Z0-9_]{4,15}$ 
匹配国内电话号码:(\d{3}-|\d{4}-)?(\d{8}|\d{7})? 
匹配腾讯QQ号:^[1-9]*[1-9][0-9]*$ 

 

--------------------------------------mysql部分-------------------------------------------

select * from table where (ID = 10)  or (ID = 32) or (ID = 22)  让结果按10, 32, 22的顺序检索出来?

Select *
from user_info
Where (ID IN (10, 32, 22))

order BY FIND_IN_SET(ID, '10, 32, 22') 


---------------------------------------linux部分-------------------------------------------

core文件是什么,有什么用?

 core是unix系统的内核。当你的程序出现内存越界的时候,操作系统会中止你的进程,并将当前内存状态倒出到core文件中,以便进一步分析。程序员可以通过core文件来找出问题所在。它记录了程序挂掉时详细的状态描述。
什么是core dump Core的意思是内存, Dump的意思是扔出来, 堆出来。开发和使用Unix程序时, 有时程序莫名其妙的down了, 却没有任何的提示(有时候会提示core dumped). 这时候可以查看一下有没有形如core.进程号的文件生成, 这个文件便是操作系统把程序down掉时的内存内容扔出来生成的,它可以做为调试程序的参考.
    core dump又叫核心转储, 当程序运行过程中发生异常, 程序异常退出时, 由操作系统把程序当前的内存状况存储在一个core文件中, 叫core dump。如何使用core文件 gdb -c core文件路径 [应用程序的路径],进去后输入where回车, 就可以显示程序在哪一行当掉的, 在哪个函数中.
为什么没有core文件生成呢? core文件的生成跟你当前系统的环境设置有关系, 可以用下面的语句设置一下, 然后再运行程序便成生成core文件.
ulimit -c unlimited core文件生成的位置一般于运行程序的路径相同, 文件名一般为core.进程号
不用core文件,程序出了问题产生信号是否知道?答:内核向进程发信号嘛。

 

共享内存除了文件映射还有什么方式?

共享内存对象映射。

二者有什么区别:

答:内存映射文件是由一个文件到一块内存的映射,使应用程序可以通过内存指针对磁盘上的文件进行访问,其过程就如同对加载了文件的内存的访问,因此内存文件映射非常适合于用来管理大文件。

 

请解释下列10个shell命令的用途
top、ps、mv、find、df、cat、chmod、chgrp、grep、wc
top:命令是Linux下常用的性能分析工具,能够实时显示系统中各个进程的资源占用状况,类似于Windows的任务管理器。 
ps:查看进程 
mv:移动或者更改文件 
find:在子目录中搜索匹配的文件 
df:linux中df命令参数功能:检查文件系统的磁盘空间占用情况。
cat:把一个或多个文件内容显示到标准输出 

chmod:改变文件属性 

chgrp:改变用户分组 

grep:在文件内进行搜索 

wc:命令的功能为统计指定文件中的字节数、字数、行数, 并将统计结果显示输出。

 

Linux文件属性有哪些?(共十位)

-rw-r--r--那个是权限符号,总共是- --- --- ---这几个位。

第一个短横处是文件类型识别符:-表示普通文件;c表示字符设备(character);b表示块设备(block);d表示目录 (directory);l表示链接文件(link);后面第一个三个连续的短横是用户权限位(User),第二个三个连续短横是组权限位 (Group),第三个三个连续短横是其他权限位(Other)。每个权限位有三个权限,r(读权限),w(写权限),x(执行权限)。如果每个权限位都 有权限存在,那么满权限的情况就是:-rwxrwxrwx;权限为空的情况就是- --- --- ---。

权限的设定可以用chmod命令,其格式位:chmod ugoa+/-/=rwx filename/directory。例如:

一个文件aaa具有完全空的权限- --- --- ---。

chmod u+rw aaa(给用户权限位设置读写权限,其权限表示为:- rw- --- ---)

chmod g+r aaa(给组设置权限为可读,其权限表示为:- --- r-- ---)

chmod ugo+rw aaa(给用户,组,其它用户或组设置权限为读写,权限表示为:- rw- rw- rw-)

如果aaa具有满权限- rwx rwx rwx。

chmod u-x aaa(去掉用户可执行权限,权限表示为:- rw- rwx rwx)

如果要给aaa赋予制定权限- rwx r-x r-x,命令为:

chmod u=rwx,go=rx aaa

 
linux查询命令
1:find / -name "文件名"    在目录结构中搜索文件,并执行指定的操作。
 
2:grep
 
3:local 文件名  ---他是 'find -name' 的另一种写法,但要比后者快得多,原因在于它不搜索具体目录,而是搜索一个数据库(/var/lib/locatedb),这个数据库中含 有本地所有文件信息。Linux系统自动创建这个数据库,并且每天自动更新一次,所以改命令查不到最新变动过的文件。为了避免这种情况,可以在使用locate之前,先使用updatedb命令,手动更新数据库。
 
4. whereis ---是定位可执行文件、源代码文件、帮助文件在文件系统中的位置。whereis命令只能用于程序名的搜索,而且只搜索二进制文件(参数-b)、man说明文件(参数-m)和源代码文件(参数-s)。如果省略参数,则返回所有信息。
 
5:which  作用是在PATH变量指定的路径中,搜索某个系统命令的位置,并且返回第一个搜索结果。也就是说,使用which命令,就可以看到某个系统命令是否存在,以及执行的到底是哪一个位置的命令。
 -------------------------------------服务器部分-------------------------------------

 
Apache与Nginx的优缺点比较 
1、nginx相对于apache的优点: 
轻量级,比apache 占用更少的内存及资源。高度模块化的设计,编写模块相对简单 
抗并发,nginx 处理请求是异步非阻塞,多个连接(万级别)可以对应一个进程,而apache 则是阻塞型的,是同步多进程模型,一个连接对应一个进程,在高并发下nginx 能保持低资源低消耗高性能 
nginx处理静态文件好,Nginx 静态处理性能比 Apache 高 3倍以上 

2、apache 相对于nginx 的优点: 
apache 的rewrite 比nginx 的rewrite 强大 ,模块非常多,基本想到的都可以找到 ,比较稳定,少bug ,nginx 的bug 相对较多 
 
3:原因:这得益于Nginx使用了最新的epoll(Linux 2.6内核)和kqueue(freebsd)网络I/O模型,而Apache则使用的是传统的select模型。目前Linux下能够承受高并发访问的 Squid、Memcached都采用的是epoll网络I/O模型。 处理大量的连接的读写,Apache所采用的select网络I/O模型非常低效。
 
 
cgi 与fastcgi的区别
cgi在2000年或更早的时候用得比较多, 以前web服务器一般只处理静态的请求,web服务器会根据这次请求的内容,然后会fork一个新进程来运行外部c程序 (或perl脚本...), 这个进程会把处理完的数据返回给web服务器,最后web服务器把内容发送给用户,刚才fork的进程也随之退出。 如果下次用户还请求改动态脚本,那么web服务器又再次fork一个新进程,周而复始的进行。

后来出现了一种更高级的方式是, web服务器可以内置perl解释器或php解释器。 也就是说这些解释器做成模块的方式,web服务器会在启动的时候就启动这些解释器。 当有新的动态请求进来时,web服务器就是自己解析这些perl或php脚本,省得重新fork一个进程,效率提高了。

fastcgi的方式是,web服务器收到一个请求时,他不会重新fork一个进程(因为这个进程在web服务器启动时就开启了,而且不会退 出),web服务器直接把内容传递给这个进程(进程间通信,但fastcgi使用了别的方式,tcp方式通信),这个进程收到请求后进行处理,把结果返回 给web服务器,最后自己接着等待下一个请求的到来,而不是退出。 
fastcgi跟cgi的区别是:
                  在web服务器方面                                                         在对数据进行处理的进程方面
cgi         fork一个新的进程进行处理                                           读取参数,处理数据,然后就结束生命期
fastcgi   用tcp方式跟远程机子上的进程或本地进程建立连接       要开启tcp端口,进入循环,等待数据的到来,处理数据


举个例子: 服务端现在有个10万个字单词, 客户每次会发来一个字符串,问以这个字符串为前缀的单词有多少个。 那么可以写一个程序,这个程序会建一棵trie树,然后每次用户请求过来时可以直接到这个trie去查找。 但是如果以cgi的方式的话,这次请求结束后这课trie也就没了,等下次再启动该进程时,又要新建一棵trie树,这样的效率就太低下了。   而用fastcgi的方式的话,这课trie树在进程启动时建立,以后就可以直接在trie树上查询指定的前缀了。

 

select, poll和epoll的区别
select
select最早于1983年出现在4.2BSD中,它通过一个select()系统调用来监视多个文件描述符的数组,当select()返回后,该数组中就绪的文件描述符便会被内核修改标志位,使得进程可以获得这些文件描述符从而进行后续的读写操作。

select目前几乎在所有的平台上支持,其良好跨平台支持也是它的一个优点,事实上从现在看来,这也是它所剩不多的优点之一。

select的一个缺点在于单个进程能够监视的文件描述符的数量存在最大限制,在Linux上一般为1024,不过可以通过修改宏定义甚至重新编译内核的方式提升这一限制。

另外,select()所维护的存储大量文件描述符的数据结构,随着文件描述符数量的增大,其复制的开销也线性增长。同时,由于网络响应时间的延迟 使得大量TCP连接处于非活跃状态,但调用select()会对所有socket进行一次线性扫描,所以这也浪费了一定的开销。

poll
poll在1986年诞生于System V Release 3,它和select在本质上没有多大差别,但是poll没有最大文件描述符数量的限制。 

poll和select同样存在一个缺点就是,包含大量文件描述符的数组被整体复制于用户态和内核的地址空间之间,而不论这些文件描述符是否就绪,它的开销随着文件描述符数量的增加而线性增大。 

另外,select()和poll()将就绪的文件描述符告诉进程后,如果进程没有对其进行IO操作,那么下次调用select()和poll() 的时候将再次报告这些文件描述符,所以它们一般不会丢失就绪的消息,这种方式称为水平触发(Level Triggered)。

epoll
直到Linux2.6才出现了由内核直接支持的实现方法,那就是epoll,它几乎具备了之前所说的一切优点,被公认为Linux2.6下性能最好的多路I/O就绪通知方法。

epoll可以同时支持水平触发和边缘触发(Edge Triggered,只告诉进程哪些文件描述符刚刚变为就绪状态,它只说一遍,如果我们没有采取行动,那么它将不会再次告知,这种方式称为边缘触发),理论上边缘触发的性能要更高一些,但是代码实现相当复杂。

epoll同样只告知那些就绪的文件描述符,而且当我们调用epoll_wait()获得就绪文件描述符时,返回的不是实际的描述符,而是一个代表 就绪描述符数量的值,你只需要去epoll指定的一个数组中依次取得相应数量的文件描述符即可,这里也使用了内存映射(mmap)技术,这样便彻底省掉了 这些文件描述符在系统调用时复制的开销。

另一个本质的改进在于epoll采用基于事件的就绪通知方式。在select/poll中,进程只有在调用一定的方法后,内核才对所有监视的文件描 述符进行扫描,而epoll事先通过epoll_ctl()来注册一个文件描述符,一旦基于某个文件描述符就绪时,内核会采用类似callback的回调 机制,迅速激活这个文件描述符,当进程调用epoll_wait()时便得到通知。

 

Memcache和Redis区别

Redis中,并不是所有的数据都一直存储在内存中的,这是和Memcached相比一个最大的区别。
Redis在很多方面具备数据库的特征,或者说就是一个数据库系统,而Memcached只是简单的K/V缓存。
他们的扩展都需要做集群;实现方式:master-slave、Hash。
在100k以上的数据中,Memcached性能要高于Redis。
如果要说内存使用效率,使用简单的key-value存储的话,Memcached的内存利用率更高,而如果Redis采用hash结构来做key-value存储,由于其组合式的压缩,其内存利用率会高于Memcached。当然,这和你的应用场景和数据特性有关。
如果你对数据持久化和数据同步有所要求,那么推荐你选择Redis,因为这两个特性Memcached都不具备。即使你只是希望在升级或者重启系统后缓存数据不会丢失,选择Redis也是明智的。
Redis和Memcache在写入性能上面差别不大,读取性能上面尤其是批量读取性能上面Memcache更强

 


使用quercus在tomcat环境中运行php程序

0311lc.com说:

简介   1
Quercus 是一个开源 PHP 5 引擎,它已经拥有了纯 Java 的完整实现。Quercus 文档指出,Quercus 在 Resin 应用服务器之上运行,利用了负载平衡、代理缓存等 Resin 特性。本文介绍了在 Apache Tomcat 之上运行 Quercus 所提供的特性。另外,本文还将展示 Quercus 针对 Web 服务和应用程序的 “PHP + Java” 混合方法的易用性和灵活性。

为何选择 Quercus?

Quercus PHP 库在 Java 中得到了完整的实现,这对 Java 和 PHP 应用程序都有好处。由于 Java 和 PHP 之间的紧密集成,Quercus 应用程序能够使用 Java 技术以及 Spring、Hibernate 和 SOA 等框架。为促进这种互操作性,Quercus 提供了一个 API,以便从 PHP 调用 Java 库。

其他好处还包括:
易于开发:PHP 库在 Java 中实现,这使它们更快速、更稳定、更易于使用。开发人员不必担心基于 C 语言的 PHP 实现中出现的分段(segmentation)错误和 C 指针溢出。
可伸缩性:作为一个基于 Java 的实现,Quercus 在 Resin 和 Apache Tomcat 等应用服务器之上运行。这样,它就可以利用应用服务器提供的所有特性,如连接池、分布式会话等。
国际化:由于 Quercus 是一个 PHP 的 Java 实现,它本身就支持 16 位 Unicode 字符串和函数。

如何使用?
1.下载quercus-4.0.3,解压到tomcat 安装目录下webapps目录下,更换名字为quercus,,然后启动tomcat,在浏览器用http://localhost:8089/quercus/访问,8089是我设置的端口,换成你自己的端口号即可,(安装tomcat没改的话默认为8080.)

这种方法最简便,不需要任何ide 编译器,只需要有记事本 或 Notepad ++等文本编辑器就可以编写php 程序。推荐使用

2.在 eclipse 中创建web 工程,加入quercus-4.0.3解压后quercus-4.0.3\WEB-INF\lib里面的jar 包(inject-16.jar,javamail-141.jar,resin.jar)
web.xml 中加入 quercus支持

<servlet>
<servlet-name>Quercus Servlet</servlet-name>
<servlet-class>com.caucho.quercus.servlet.QuercusServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Quercus Servlet</servlet-name>
<url-pattern>*.php</url-pattern>
</servlet-mapping>
1
2
3
4
5
6
7
8
web.xml 中加入quercus-4.0.3解压后的欢迎页 index.php

出现这个页面说明配置成功,可以随意写其他php 程序啦。
https://blog.csdn.net/bruce_shan/article/details/54728570


5种php加密工具zendGuard、ionCube、SourceCop、SourceGuardian、phpShield

0311lc.com说:

HP做桌面应用的想法: 除去icudt55.dll,PHP7用7ZIP压缩后不足7MB,而PHP自带了SQLite和CLI HTTP Server,用户打开浏览器就能访问PHP开发的桌面应用.如果源代码不想被别人看到,可以用php-beast之类的工具进行加密. 还有,我想为什么PHP就不适合用来进行数据处理,毕竟就速度而言,PHP5都比Python快,更不用说PHP7了.

————————————————————————————–

Zend grard Zend Encoder 目前市价为 US$960、SafeGuard Suite 更是到 US$2,920 以上的天价,而且 US$2,920 还只能使用一年。但由于破解档流通快速,早期也是加密 PHP 的最佳解决方案,因此可以说是市占率第一名的 PHP 原始码加密软件,连虚拟主机商也为了要执行 Zend
1、ZendGuard
Zend Encoder 目前市价为 US$960、SafeGuard Suite 更是到 US$2,920 以上的天价,而且 US$2,920 还只能使用一年。但由于破解档流通快速,早期也是加密 PHP 的最佳解决方案,因此可以说是市占率第一名的 PHP 原始码加密软件,连虚拟主机商也为了要执行 Zend 加密过的档案,不得不纷纷安装 Zend Optimizer 。
直到现在 Zend 对于 Encoder 的态度消极已经是众所皆知,久久才出现一次新版本,因此也开始让其它的 Encoder 冒出头了。
到上个月 Zend Encoder 破解的消息甚嚣尘上,更是让对于想保护自己 PHP 原始码的公司及设计师开始寻求替代方案。
由于目前大部份的虚拟主机都已安装 Zend Optimizer (Zend Encoder 的执行环境),因此本次 PHP 原始码加密软件的测试重点为「不需在服务器设定或安装任何软件」。
2、ionCube Standalone Encoder (US$199 起)
http://www.ioncube.com/sa_encoder.php
ionCube 在国外已经是软件公司取代 Zend Encoder 的不二选择,知名的 PHP 购物车 X-Cart 就是采用
ionCube Standalone Encoder 加密原始码。服务器端不需安装任何软件,只要把 Loader 放在程序的目录里面就可以了。
20051125_01.gif
(Windows+IIS 下执行加密过后的 phpinfo(); )
20051125_02.gif
(Linux+Apache 下执行加密过后的 phpinfo(); )
3、SourceCop (US$30)
http://www.sourcecop.com/
服务器完全不用外挂任何 Loader 及 Module,完全用 PHP 的方式来加密程序,有点功力的人追踪一下就能看出编码方式了,所以只能防君子不能防小人。
20051125_03.gif
(编码后的程序)
20051125_04.gif
(sourcecop 的译码加载程序)
注:这里也有人有说明将原始码还原的方式。
4、SourceGuardian (US$250)
这家应该算是相当知名的PHP加密软件,不过服务器端需要外挂 Loader,因此其它测试省略。
测试结果: (失败! 需安装 Loader)
PHP script i.php is protected by SourceGuardian and requires the SourceGuardian loader ixed.4.3ev.win. The SourceGuardian loader has not been installed, or is not installed correctly. Please visit the SourceGuardian php encoder site to download required loader.
5、phpShield ( US$99)
http://www.phpshield.com
操作就跟一般的 Encoder 一样简单,因为 phpShield 跟 SourceGuardian 的试用流程、Email 内容、画面、压缩档都一模一样,有可能是 SourceGuardian 的简易版,因为我没用过旧版,也有可能是 SourceGuardian 的旧版便宜卖。
测试结果: (失败! 需加装 Loader,讯息也同SourceGuardian )
PHP script phpinfo.php is protected by phpSHIELD and requires file phpshield.4.3.11ev.win or phpshield.4.3ev.win.
Please read phpSHIELD protected scripts manual.
总结:
ionCube Standalone Encoder 不论功能性、方便性都是四者当中最好的,而且不需在服务器端安装任何软件,在预算许可的范围下 ionCube Standalone Encoder 的确是最好的选择。
如果不介意主机需安装加载器,只是要单纯保护程序代码不妨选择 phpShield 。

如何安装ioncube扩展对PHP代码加密

0311lc.com说:
道专业版本的核心代码都是加密的(前端的html, css, js, 配置,语言项是开源的)的,使用的加密软件是 ioncube,因此要能运行禅道专业版本的软件,先要按照ioncube扩展。

一、下载loader-wizard.php(支持php5.3、php5.4、php5.5、php5.6版本)

ioncube提供了一个安装的向导程序,可以非常方便的帮助检测php的运行环境,自动给出提示。

1.1 通过下面的地址下载loader-wizard:http://www.ioncube.com/loader-wizard/loader-wizard.zip

1.2 下载之后,将其解压缩,到apache的www或者htdoc目录。

二、运行loader-wizard.php程序

2.1 使用浏览器访问loader-wizard.php 比如 http://localhost/loader-wizard.php 实际的访问路径根据情况修改。

2.2 这个loader程序经过计算之后,会自动给出提示:

  • 根据这个向导程序的提示,下载相应的解密软件。
  • 将下载下来的解密软件放在它指定的目录中。
  • 下载向导程序计算出来新的php.ini文件,替换系统原来的php.ini文件。
  • 重新启动apache。

2.3 验证是否安装成功

重新启动之后,再次访问loader.php,如果安装成功,系统会提示。

看到这个界面,就表示解密软件已经安装成功了。


swoole+websocket+redis

0311lc.com说:

 

环境:ubuntu + php + swoole扩展 + redis + mysql

Redis 实现每个连接websocket的服务都唯一绑定一个用户。通过 用户账号 = websocket fd 存到redis中。

Mysql 实现离线消息池。如果一个用户不在线,则其他用户发送给他的消息暂时存储在mysql。待该用户上线时,再从离线消息池取出发送。

具体参考代码和相应注释:

服务端代码:

<?php
$server = new swoole_websocket_server("0.0.0.0", 9052);
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$db = new mysqli('127.0.0.1', 'test', 'test', 'thinkphp5');

$server->on('open', function (swoole_websocket_server $server, $request) {
    echo "server: handshake success with fd{$request->fd}\n";//$request->fd 是客户端id
});

$server->on('message', function (swoole_websocket_server $server, $frame) {
    $data = json_decode($frame->data,true); 
    if($data['flag'] == 'init'){
        //用户刚连接的时候初始化,每个用户登录时记录该用户对应的fd
        $GLOBALS['redis']->set($data['from'], $frame->fd);
        //处理发给该用户的离线消息
        $sql = "SELECT `from`,content FROM thinkphp5.app_offline WHERE `to`='{$data['from']}' AND `from`='{$data['to']}' AND `status`='0' ORDER BY addtime ASC;";
        if ($result = $GLOBALS['db']->query($sql)) {
            $re = array();
            while ($row = $result->fetch_assoc()) {
                array_push($re, $row);
            }
            $result->free();
            foreach($re as $content){
                $content = json_encode($content);
                $server->push($frame->fd , $content);
            }
            //设置消息池中的消息为已发送
            $sql = "UPDATE thinkphp5.app_offline SET `status`=1 WHERE `to`='{$data['from']}' AND `from`='{$data['to']}';";
            $GLOBALS['db']->query($sql);
        }
    }else if($data['flag'] == 'msg'){
        //非初始化的信息发送,一对一聊天,根据每个用户对应的fd发给特定用户
        $tofd = $GLOBALS['redis']->get($data['to']); //消息要发给谁
        $fds = []; //所有在线的用户(打开聊天窗口的用户)
        foreach($server->connections as $fd){
            array_push($fds, $fd);
        }
        if(in_array($tofd,$fds)){
            $tmp['from'] = $data['from']; //消息来自于谁
            $tmp['content']  = $data['content']; //消息内容
            $re = json_encode($tmp);
            $server->push($tofd , $re);
        }else{
            //该玩家不在线(不在聊天室内),将信息发送到离线消息池
            $time = time();
            $sql = "INSERT INTO thinkphp5.app_offline (`to`,`from`,`content`,`status`,`addtime`) VALUES ('{$data['to']}','{$data['from']}','{$data['content']}','0','{$time}');";
            $GLOBALS['db']->query($sql);
        }
    }else if($data['flag'] == 'group'){
        //todo 群聊
        
    }else if($data['flag'] == 'all'){
        //全站广播
        foreach($server->connections as $fd){
            $server->push($fd , $data);
        }
    }  
});

$server->on('close', function ($ser, $fd) {
    echo "client {$fd} closed\n";
});

$server->start();

 

客户端代码:

 
<!DOCTYPE html>
<html>
<head>
    <title>XST-app</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7" />
    <meta name="viewport" content="width=device-width, initial-scale=0.0, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0" />
    <meta name="keywords" content="test" />
    <meta name="description" content="test" />
    <meta name="author" content="XST-APP" />
    <meta content="yes" name="apple-mobile-web-app-capable" />
    <meta content="black" name="apple-mobile-web-app-status-bar-style" />
    <meta content="telephone=no" name="format-detection" />
  <style type="text/css">
    body{background:url(/static/images/yuyin_bg.jpg);background-size:100%;}
    @media all and (min-width: 640px) {
        body,html,.wenwen-footer,.speak_window{width:640px!important;margin:0 auto}
        .speak_window,.wenwen-footer{left:50%!important;margin-left:-320px}
    }
    input,button{outline:none;}
    .wenwen-footer{width:100%;position:fixed;bottom:-5px;left:0;background:#fff;padding:3%;border-top:solid 1px #ddd;box-sizing:border-box;}
    .wenwen_btn,.wenwen_help{width:15%;text-align:center;}
    .wenwen_btn img,.wenwen_help img{height:40px;}
    .wenwen_text{height:40px;border-radius:5px;border:solid 1px #636162;box-sizing:border-box;width:66%;text-align:center;overflow:hidden;margin-left:2%;}
    .circle-button{padding:0 5px;}
    .wenwen_text .circle-button{font-size:14px;color:#666;line-height:38px;}
    .write_box{background:#fff;width:100%;height:40px;line-height:40px;}
    .write_box input{height:40px;padding:0 5px;line-height:40px;width:100%;box-sizing:border-box;border:0;}
    .wenwen_help button{width:95%;background:#42929d;color:#fff;border-radius:5px;border:0;height:40px;}
    #wenwen{height:100%;}
    .speak_window{overflow-y:scroll;height:100%;width:100%;position:fixed;top:50px;left:0;}
    .speak_box{margin-bottom:70px;padding:10px;}
    .question,.answer{margin-bottom:1rem;}
    .question{text-align:right;}
    .question>div{display:inline-block;}
    .left{float:left;}
    .right{float:right;}
    .clear{clear:both;}
    .heard_img{height:60px;width:60px;border-radius:5px;overflow:hidden;background:#ddd;}
    .heard_img img{width:100%;height:100%}
    .question_text,.answer_text{box-sizing:border-box;position:relative;display:table-cell;min-height:60px;}
    .question_text{padding-right:20px;}
    .answer_text{padding-left:20px;}
    .question_text p,.answer_text p{border-radius:10px;padding:.5rem;margin:0;font-size:14px;line-height:28px;box-sizing:border-box;vertical-align:middle;display:table-cell;height:30px;word-wrap:break-word;}
    .answer_text p{background:#fff;}
    .question_text p{background:#42929d;color:#fff;text-align:left;}
    .question_text i,.answer_text i{width:0;height:0;border-top:5px solid transparent;border-bottom:5px solid transparent;position:absolute;top:25px;}
    .answer_text i{border-right:10px solid #fff;left:10px;}
    .question_text i{border-left:10px solid #42929d;right:10px;}
    .answer_text p a{color:#42929d;display:inline-block;}
    .write_list{position:absolute;left:0;width:100%;background:#fff;border-top:solid 1px #ddd;padding:5px;line-height:30px;}
  </style>
</head>

<body>
<div id="header" class="head">
        <div class="wrap">
                <i class="menu_back"><a href="javascript:history.go(-1);"></a></i>
                <div class="title">
                        <span class="title_d"><p>与 {$tonickname} 的聊天</p></span>
                        <div class="clear"></div>
                </div>
                <!--i class="menu_share"></i-->
        </div>
</div>
<input type="hidden" name="myemail" id="myemail" value="{$myemail}" />
<input type="hidden" name="mynickname" id="mynickname" value="{$mynickname}" />
<input type="hidden" name="myavatar" id="myavatar" value="{$myavatar}" />
<input type="hidden" name="toemail" id="toemail" value="{$toemail}" />
<input type="hidden" name="tonickname" id="tonickname" value="{$tonickname}" />
<input type="hidden" name="toavatar" id="toavatar" value="{$toavatar}" />

<!-- 对话内容 -->
<div class="speak_window">
    <div class="speak_box">

    </div>
</div>

<!-- 内容输入-->
<div class="wenwen-footer">
    <div class="wenwen_btn left"><img src="/static/images/jp_btn.png"></div>
    <div class="wenwen_text left">
        <div class="write_box"><input type="text" class="left" onKeyUp="keyup()" maxlength="100" placeholder="请输入信息(100字以内)..." /></div>   
    </div>
    <div class="wenwen_help right">
            <button onClick="send()" class="right">发送</button>
    </div>
    <div style="opacity:0;" class="clear"></div>
</div>

<script type="text/javascript">
    if ("WebSocket" in window){
        var ws = new WebSocket("ws://192.168.0.1:9052");
        ws.onopen = function(){
            console.log("握手成功");
            var myemail = $("#myemail").val();
            var toemail = $("#toemail").val();
            var arr = {"flag":"init","from":myemail,"to":toemail};
            var str = JSON.stringify(arr);
            ws.send(str);
        };
        ws.onmessage = function(e){
            var toemail = $("#toemail").val();
            var toavatar = $("#toavatar").val();
            var obj = JSON.parse(e.data);
            console.log(e.data);
            //但同时与两个人聊天时,可能两个人的消息都会出现在当前窗口,所以此处加个判断,此窗口只接收当前聊天对象的消息,其他则忽略
            if(obj.from === toemail){
                var ans  = '<div class="answer"><div class="heard_img left"><img src="'+toavatar+'"></div>';
                    ans += '<div class="answer_text"><p>'+obj.content+'</p><i></i>';
                    ans += '</div></div>';
                    $('.speak_box').append(ans);
                    for_bottom();
            }
        };
        ws.onerror = function(){
            console.log("error");
            var  str  = '<div class="question">';
            str += '<div class="heard_img right"><img src="/static/images/xitong.jpg"></div>';
            str += '<div class="question_text clear"><p>聊天服务器出现异常,暂时无法提供服务。</p><i></i>';
            str += '</div></div>';
            $('.speak_box').append(str);
            $('.write_box input').val('');
            $('.write_box input').focus();
            autoWidth();
            for_bottom();
        };

        function send() {
            var content = $('.write_box input').val();
        if(content === ''){
            alert('请输入消息!');
            $('.write_box input').focus();
        }else{
                var toemail = $("#toemail").val();
                var myemail = $("#myemail").val();
                var myavatar = $("#myavatar").val();
                var arr = {"flag":"msg","to":toemail,"from":myemail,"content":content};
                var msg = JSON.stringify(arr);
                console.log(msg);
                ws.send(msg);    
                var  str  = '<div class="question">';
                str += '<div class="heard_img right"><img src="'+myavatar+'"></div>';
                str += '<div class="question_text clear"><p>'+content+'</p><i></i>';
                str += '</div></div>';
            $('.speak_box').append(str);
            $('.write_box input').val('');
            $('.write_box input').focus();
            autoWidth();
            for_bottom();
            }
        
        }
    }else{
        alert("您的浏览器不支持 WebSocket!");
    }
           
    function for_bottom(){
    var speak_height = $('.speak_box').height();
    $('.speak_box,.speak_window').animate({scrollTop:speak_height},500);
    }
    
    function autoWidth(){
    $('.question_text').css('max-width',$('.question').width()-60);
    }
    
    autoWidth();
    
</script>

</body>
</html>

 

 

数据表结构:

CREATE TABLE `app_offline` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `from` varchar(50) DEFAULT NULL COMMENT '离线发送方',
  `to` varchar(50) DEFAULT NULL COMMENT '离线接收方',
  `content` varchar(1000) DEFAULT NULL COMMENT '发送的离线内容',
  `status` tinyint(4) DEFAULT '0' COMMENT '发送状态:0-未发送,1-已发送',
  `addtime` int(11) DEFAULT NULL COMMENT '发送方发送时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8

 


巧用PHP中__get()魔术方法

0311lc.com说:

PHP中的魔术方法有很多,这些魔术方法可以让PHP脚本在某些特定的情况下自动调用。比如 __construct() 每次实例化一个类都会先调用该方法进行初始化。这里我们讲一下__get() 魔术方法的使用。读取不可访问属性的值时,__get() 会被调用。也就是,当想要获取一个类的私有属性,或者获取一个类并为定义的属性时。该魔术方法会被调用。

下面有段代码:

class Model
{

   //不存在的成员属性自动调用
  function __get($name) 
  {
         //自动加载数据库
        if(substr($name, 0,2) =='db'){
            $config = strtolower(substr($name, 2));
            if(empty($this->objDb)){
                $this->objDb = new LibDatabase($config);
            }else{
                $this->objDb->config($config);
            }
            return $this->objDb; 
        }

        // 自动加载redis
        if(substr($name, 0,5) =='redis'){
            $config = strtolower(substr($name, 5));
            if(empty($this->objRedis)){
                $this->objRedis = new LibRedis($config);
            }else{
                $this->objRedis->config($config);
            }
            return $this->objRedis;
        }

        //自动加载excel插件
        if(substr($name, 0,5) =='excel'){
            if(empty($this->objExcel)){
                $this->objExcel = new LibExcel();
            }
            return $this->objExcel;
        }
        throw new LinkException("变量{$name}不被支持,请预先Model中定义",EXCEPT_CORE);
    }
}

?>

首先,该Model类有只有一个__get() 方法,没有定义其他属性,所有只要是访问这个Model类的属性,都会来调用这个__get() 方法。而传入的参数$name就是想要调用Model类的属性。

其次,__get() 方法里有3个判断,分别用于返回一个LibDatabase数据库类和一个LibRedis缓存类和一个LibExcel 的Excel插件类的实例。

假设$mod 是Model的一个对象。我们来分析以下三中情况:

1、$mod->dbconfsys->getAll($sql);

2、$mod->redisconfsys->get($key);

3、$mod->excel->export($data);

第一个:访问Model类的dbconfsys属性。但是Model类中并没有该属性。所以 __get() 的第一个判读成立,那么会返回LibDatabase(‘confsys’)的实例。这里confsys其实是一个数据库的配置。如果有多个数据库的配置比如confadmin、conftest等,都可以使用dbconfadmin和dbconftest来实例化该数据库的一个连接对象。当然连接的处理以及数据处理是在LibDatabase里实现的。最后调用该实例的getAll方法执行sql语句。

第二个:访问Model类的redisconfsys属性,同理,此时 __get() 的第二个判断成立。返回的是LibRedis(‘confsys’)的实例。这里的confsys则是一个redis的配置。像数据库实例一样,如果有多个配置,也是同样的处理方式。最后调用该实例的get方法获取某个键的值。

第三个:访问Model类的excel 属性,此时__get() 的第三个判断成立。返回的是LibExcel()的实例。最后调用export方法导出数据。

这个Model类可以作为基础的底层模型。然后系统中所有数据表的模型或者每个模块功能的模型都继承Model,同样可以使用该Model的功能,这里需要注意的是每种对象的调用都需要先早Model中做好判断处理。


js 加密解密

0311lc.com说:

其他的加解密 参考

https://blog.csdn.net/zhihua_w/article/details/79388297

https://blog.csdn.net/u010081710/article/details/47398315

https://www.cnblogs.com/claireyuancy/p/6805790.html

 

某招生考试网上信息管理系统例子

	$('#loginId').val($Jquery.encrypt($('#loginId').val()));
	$('#password').val($Jquery.encrypt($('#password').val()));

 

(function(a, b) {
    a.$Jquery = b();
    a.$Jquery.encrypt = function(g) {
        var f = a.$Jquery.enc.Utf8.parse(g);
        var d = a.$Jquery.enc.Utf8.parse(c);
        var e = a.$Jquery.AES.encrypt(f, d, {
            mode: a.$Jquery.mode.ECB,
            padding: a.$Jquery.pad.Pkcs7
        });
        return e.toString()
    };
    a.$Jquery.decrypt = function(f) {
        var d = a.$Jquery.enc.Utf8.parse(c);
        var e = a.$Jquery.AES.decrypt(f, d, {
            mode: a.$Jquery.mode.ECB,
            padding: a.$Jquery.pad.Pkcs7
        });
        return a.$Jquery.enc.Utf8.stringify(e).toString()
    };
    var c = "o7H8uIM2852Hy6l2"
} (this,
function() {
    var a = a || (function(f, h) {
        var k = Object.create || (function() {
            function p() {}
            return function(r) {
                var q;
                p.prototype = r;
                q = new p();
                p.prototype = null;
                return q
            }
        } ());
        var b = {};
        var c = b.lib = {};
        var l = c.Base = (function() {
            return {
                extend: function(q) {
                    var p = k(this);
                    if (q) {
                        p.mixIn(q)
                    }
                    if (!p.hasOwnProperty("init") || this.init === p.init) {
                        p.init = function() {
                            p.$super.init.apply(this, arguments)
                        }
                    }
                    p.init.prototype = p;
                    p.$super = this;
                    return p
                },
                create: function() {
                    var p = this.extend();
                    p.init.apply(p, arguments);
                    return p
                },
                init: function() {},
                mixIn: function(q) {
                    for (var p in q) {
                        if (q.hasOwnProperty(p)) {
                            this[p] = q[p]
                        }
                    }
                    if (q.hasOwnProperty("toString")) {
                        this.toString = q.toString
                    }
                },
                clone: function() {
                    return this.init.prototype.extend(this)
                }
            }
        } ());
        var n = c.WordArray = l.extend({
            init: function(q, p) {
                q = this.words = q || [];
                if (p != h) {
                    this.sigBytes = p
                } else {
                    this.sigBytes = q.length * 4
                }
            },
            toString: function(p) {
                return (p || i).stringify(this)
            },
            concat: function(v) {
                var s = this.words;
                var r = v.words;
                var p = this.sigBytes;
                var u = v.sigBytes;
                this.clamp();
                if (p % 4) {
                    for (var t = 0; t < u; t++) {
                        var q = (r[t >>> 2] >>> (24 - (t % 4) * 8)) & 255;
                        s[(p + t) >>> 2] |= q << (24 - ((p + t) % 4) * 8)
                    }
                } else {
                    for (var t = 0; t < u; t += 4) {
                        s[(p + t) >>> 2] = r[t >>> 2]
                    }
                }
                this.sigBytes += u;
                return this
            },
            clamp: function() {
                var q = this.words;
                var p = this.sigBytes;
                q[p >>> 2] &= 4294967295 << (32 - (p % 4) * 8);
                q.length = f.ceil(p / 4)
            },
            clone: function() {
                var p = l.clone.call(this);
                p.words = this.words.slice(0);
                return p
            },
            random: function(v) {
                var u = [];
                var s = (function(x) {
                    var x = x;
                    var w = 987654321;
                    var r = 4294967295;
                    return function() {
                        w = (36969 * (w & 65535) + (w >> 16)) & r;
                        x = (18000 * (x & 65535) + (x >> 16)) & r;
                        var y = ((w << 16) + x) & r;
                        y /= 4294967296;
                        y += 0.5;
                        return y * (f.random() > 0.5 ? 1 : -1)
                    }
                });
                for (var q = 0,
                p; q < v; q += 4) {
                    var t = s((p || f.random()) * 4294967296);
                    p = t() * 987654071;
                    u.push((t() * 4294967296) | 0)
                }
                return new n.init(u, v)
            }
        });
        var o = b.enc = {};
        var i = o.Hex = {
            stringify: function(r) {
                var t = r.words;
                var q = r.sigBytes;
                var s = [];
                for (var p = 0; p < q; p++) {
                    var u = (t[p >>> 2] >>> (24 - (p % 4) * 8)) & 255;
                    s.push((u >>> 4).toString(16));
                    s.push((u & 15).toString(16))
                }
                return s.join("")
            },
            parse: function(r) {
                var p = r.length;
                var s = [];
                for (var q = 0; q < p; q += 2) {
                    s[q >>> 3] |= parseInt(r.substr(q, 2), 16) << (24 - (q % 8) * 4)
                }
                return new n.init(s, p / 2)
            }
        };
        var e = o.Latin1 = {
            stringify: function(s) {
                var t = s.words;
                var r = s.sigBytes;
                var p = [];
                for (var q = 0; q < r; q++) {
                    var u = (t[q >>> 2] >>> (24 - (q % 4) * 8)) & 255;
                    p.push(String.fromCharCode(u))
                }
                return p.join("")
            },
            parse: function(r) {
                var p = r.length;
                var s = [];
                for (var q = 0; q < p; q++) {
                    s[q >>> 2] |= (r.charCodeAt(q) & 255) << (24 - (q % 4) * 8)
                }
                return new n.init(s, p)
            }
        };
        var d = o.Utf8 = {
            stringify: function(p) {
                try {
                    return decodeURIComponent(escape(e.stringify(p)))
                } catch(q) {
                    throw new Error("Malformed UTF-8 data")
                }
            },
            parse: function(p) {
                return e.parse(unescape(encodeURIComponent(p)))
            }
        };
        var j = c.BufferedBlockAlgorithm = l.extend({
            reset: function() {
                this._data = new n.init();
                this._nDataBytes = 0
            },
            _append: function(p) {
                if (typeof p == "string") {
                    p = d.parse(p)
                }
                this._data.concat(p);
                this._nDataBytes += p.sigBytes
            },
            _process: function(y) {
                var s = this._data;
                var z = s.words;
                var p = s.sigBytes;
                var v = this.blockSize;
                var x = v * 4;
                var w = p / x;
                if (y) {
                    w = f.ceil(w)
                } else {
                    w = f.max((w | 0) - this._minBufferSize, 0)
                }
                var u = w * v;
                var t = f.min(u * 4, p);
                if (u) {
                    for (var r = 0; r < u; r += v) {
                        this._doProcessBlock(z, r)
                    }
                    var q = z.splice(0, u);
                    s.sigBytes -= t
                }
                return new n.init(q, t)
            },
            clone: function() {
                var p = l.clone.call(this);
                p._data = this._data.clone();
                return p
            },
            _minBufferSize: 0
        });
        var g = c.Hasher = j.extend({
            cfg: l.extend(),
            init: function(p) {
                this.cfg = this.cfg.extend(p);
                this.reset()
            },
            reset: function() {
                j.reset.call(this);
                this._doReset()
            },
            update: function(p) {
                this._append(p);
                this._process();
                return this
            },
            finalize: function(p) {
                if (p) {
                    this._append(p)
                }
                var q = this._doFinalize();
                return q
            },
            blockSize: 512 / 32,
            _createHelper: function(p) {
                return function(r, q) {
                    return new p.init(q).finalize(r)
                }
            },
            _createHmacHelper: function(p) {
                return function(r, q) {
                    return new m.HMAC.init(p, q).finalize(r)
                }
            }
        });
        var m = b.algo = {};
        return b
    } (Math)); (function() {
        var g = a;
        var b = g.lib;
        var c = b.WordArray;
        var f = g.enc;
        var e = f.Base64 = {
            stringify: function(n) {
                var p = n.words;
                var r = n.sigBytes;
                var k = this._map;
                n.clamp();
                var o = [];
                for (var m = 0; m < r; m += 3) {
                    var u = (p[m >>> 2] >>> (24 - (m % 4) * 8)) & 255;
                    var s = (p[(m + 1) >>> 2] >>> (24 - ((m + 1) % 4) * 8)) & 255;
                    var q = (p[(m + 2) >>> 2] >>> (24 - ((m + 2) % 4) * 8)) & 255;
                    var t = (u << 16) | (s << 8) | q;
                    for (var l = 0; (l < 4) && (m + l * 0.75 < r); l++) {
                        o.push(k.charAt((t >>> (6 * (3 - l))) & 63))
                    }
                }
                var h = k.charAt(64);
                if (h) {
                    while (o.length % 4) {
                        o.push(h)
                    }
                }
                return o.join("")
            },
            parse: function(o) {
                var k = o.length;
                var l = this._map;
                var i = this._reverseMap;
                if (!i) {
                    i = this._reverseMap = [];
                    for (var h = 0; h < l.length; h++) {
                        i[l.charCodeAt(h)] = h
                    }
                }
                var n = l.charAt(64);
                if (n) {
                    var m = o.indexOf(n);
                    if (m !== -1) {
                        k = m
                    }
                }
                return d(o, k, i)
            },
            _map: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
        };
        function d(p, l, k) {
            var n = [];
            var m = 0;
            for (var j = 0; j < l; j++) {
                if (j % 4) {
                    var h = k[p.charCodeAt(j - 1)] << ((j % 4) * 2);
                    var o = k[p.charCodeAt(j)] >>> (6 - (j % 4) * 2);
                    n[m >>> 2] |= (h | o) << (24 - (m % 4) * 8);
                    m++
                }
            }
            return c.create(n, m)
        }
    } ()); (function(d) {
        var b = a;
        var c = b.lib;
        var j = c.WordArray;
        var f = c.Hasher;
        var k = b.algo;
        var g = []; (function() {
            for (var n = 0; n < 64; n++) {
                g[n] = (d.abs(d.sin(n + 1)) * 4294967296) | 0
            }
        } ());
        var l = k.MD5 = f.extend({
            _doReset: function() {
                this._hash = new j.init([1732584193, 4023233417, 2562383102, 271733878])
            },
            _doProcessBlock: function(t, o) {
                for (var J = 0; J < 16; J++) {
                    var n = o + J;
                    var p = t[n];
                    t[n] = ((((p << 8) | (p >>> 24)) & 16711935) | (((p << 24) | (p >>> 8)) & 4278255360))
                }
                var y = this._hash.words;
                var B = t[o + 0];
                var A = t[o + 1];
                var z = t[o + 2];
                var x = t[o + 3];
                var w = t[o + 4];
                var v = t[o + 5];
                var u = t[o + 6];
                var s = t[o + 7];
                var r = t[o + 8];
                var q = t[o + 9];
                var I = t[o + 10];
                var G = t[o + 11];
                var F = t[o + 12];
                var E = t[o + 13];
                var D = t[o + 14];
                var C = t[o + 15];
                var O = y[0];
                var N = y[1];
                var L = y[2];
                var K = y[3];
                O = i(O, N, L, K, B, 7, g[0]);
                K = i(K, O, N, L, A, 12, g[1]);
                L = i(L, K, O, N, z, 17, g[2]);
                N = i(N, L, K, O, x, 22, g[3]);
                O = i(O, N, L, K, w, 7, g[4]);
                K = i(K, O, N, L, v, 12, g[5]);
                L = i(L, K, O, N, u, 17, g[6]);
                N = i(N, L, K, O, s, 22, g[7]);
                O = i(O, N, L, K, r, 7, g[8]);
                K = i(K, O, N, L, q, 12, g[9]);
                L = i(L, K, O, N, I, 17, g[10]);
                N = i(N, L, K, O, G, 22, g[11]);
                O = i(O, N, L, K, F, 7, g[12]);
                K = i(K, O, N, L, E, 12, g[13]);
                L = i(L, K, O, N, D, 17, g[14]);
                N = i(N, L, K, O, C, 22, g[15]);
                O = e(O, N, L, K, A, 5, g[16]);
                K = e(K, O, N, L, u, 9, g[17]);
                L = e(L, K, O, N, G, 14, g[18]);
                N = e(N, L, K, O, B, 20, g[19]);
                O = e(O, N, L, K, v, 5, g[20]);
                K = e(K, O, N, L, I, 9, g[21]);
                L = e(L, K, O, N, C, 14, g[22]);
                N = e(N, L, K, O, w, 20, g[23]);
                O = e(O, N, L, K, q, 5, g[24]);
                K = e(K, O, N, L, D, 9, g[25]);
                L = e(L, K, O, N, x, 14, g[26]);
                N = e(N, L, K, O, r, 20, g[27]);
                O = e(O, N, L, K, E, 5, g[28]);
                K = e(K, O, N, L, z, 9, g[29]);
                L = e(L, K, O, N, s, 14, g[30]);
                N = e(N, L, K, O, F, 20, g[31]);
                O = m(O, N, L, K, v, 4, g[32]);
                K = m(K, O, N, L, r, 11, g[33]);
                L = m(L, K, O, N, G, 16, g[34]);
                N = m(N, L, K, O, D, 23, g[35]);
                O = m(O, N, L, K, A, 4, g[36]);
                K = m(K, O, N, L, w, 11, g[37]);
                L = m(L, K, O, N, s, 16, g[38]);
                N = m(N, L, K, O, I, 23, g[39]);
                O = m(O, N, L, K, E, 4, g[40]);
                K = m(K, O, N, L, B, 11, g[41]);
                L = m(L, K, O, N, x, 16, g[42]);
                N = m(N, L, K, O, u, 23, g[43]);
                O = m(O, N, L, K, q, 4, g[44]);
                K = m(K, O, N, L, F, 11, g[45]);
                L = m(L, K, O, N, C, 16, g[46]);
                N = m(N, L, K, O, z, 23, g[47]);
                O = h(O, N, L, K, B, 6, g[48]);
                K = h(K, O, N, L, s, 10, g[49]);
                L = h(L, K, O, N, D, 15, g[50]);
                N = h(N, L, K, O, v, 21, g[51]);
                O = h(O, N, L, K, F, 6, g[52]);
                K = h(K, O, N, L, x, 10, g[53]);
                L = h(L, K, O, N, I, 15, g[54]);
                N = h(N, L, K, O, A, 21, g[55]);
                O = h(O, N, L, K, r, 6, g[56]);
                K = h(K, O, N, L, C, 10, g[57]);
                L = h(L, K, O, N, u, 15, g[58]);
                N = h(N, L, K, O, E, 21, g[59]);
                O = h(O, N, L, K, w, 6, g[60]);
                K = h(K, O, N, L, G, 10, g[61]);
                L = h(L, K, O, N, z, 15, g[62]);
                N = h(N, L, K, O, q, 21, g[63]);
                y[0] = (y[0] + O) | 0;
                y[1] = (y[1] + N) | 0;
                y[2] = (y[2] + L) | 0;
                y[3] = (y[3] + K) | 0
            },
            _doFinalize: function() {
                var r = this._data;
                var w = r.words;
                var t = this._nDataBytes * 8;
                var u = r.sigBytes * 8;
                w[u >>> 5] |= 128 << (24 - u % 32);
                var s = d.floor(t / 4294967296);
                var o = t;
                w[(((u + 64) >>> 9) << 4) + 15] = ((((s << 8) | (s >>> 24)) & 16711935) | (((s << 24) | (s >>> 8)) & 4278255360));
                w[(((u + 64) >>> 9) << 4) + 14] = ((((o << 8) | (o >>> 24)) & 16711935) | (((o << 24) | (o >>> 8)) & 4278255360));
                r.sigBytes = (w.length + 1) * 4;
                this._process();
                var q = this._hash;
                var v = q.words;
                for (var p = 0; p < 4; p++) {
                    var n = v[p];
                    v[p] = (((n << 8) | (n >>> 24)) & 16711935) | (((n << 24) | (n >>> 8)) & 4278255360)
                }
                return q
            },
            clone: function() {
                var n = f.clone.call(this);
                n._hash = this._hash.clone();
                return n
            }
        });
        function i(q, p, y, v, o, u, r) {
            var w = q + ((p & y) | (~p & v)) + o + r;
            return ((w << u) | (w >>> (32 - u))) + p
        }
        function e(q, p, y, v, o, u, r) {
            var w = q + ((p & v) | (y & ~v)) + o + r;
            return ((w << u) | (w >>> (32 - u))) + p
        }
        function m(q, p, y, v, o, u, r) {
            var w = q + (p ^ y ^ v) + o + r;
            return ((w << u) | (w >>> (32 - u))) + p
        }
        function h(q, p, y, v, o, u, r) {
            var w = q + (y ^ (p | ~v)) + o + r;
            return ((w << u) | (w >>> (32 - u))) + p
        }
        b.MD5 = f._createHelper(l);
        b.HmacMD5 = f._createHmacHelper(l)
    } (Math)); (function() {
        var h = a;
        var e = h.lib;
        var g = e.WordArray;
        var c = e.Hasher;
        var f = h.algo;
        var b = [];
        var d = f.SHA1 = c.extend({
            _doReset: function() {
                this._hash = new g.init([1732584193, 4023233417, 2562383102, 271733878, 3285377520])
            },
            _doProcessBlock: function(o, k) {
                var u = this._hash.words;
                var s = u[0];
                var r = u[1];
                var q = u[2];
                var p = u[3];
                var m = u[4];
                for (var l = 0; l < 80; l++) {
                    if (l < 16) {
                        b[l] = o[k + l] | 0
                    } else {
                        var j = b[l - 3] ^ b[l - 8] ^ b[l - 14] ^ b[l - 16];
                        b[l] = (j << 1) | (j >>> 31)
                    }
                    var v = ((s << 5) | (s >>> 27)) + m + b[l];
                    if (l < 20) {
                        v += ((r & q) | (~r & p)) + 1518500249
                    } else {
                        if (l < 40) {
                            v += (r ^ q ^ p) + 1859775393
                        } else {
                            if (l < 60) {
                                v += ((r & q) | (r & p) | (q & p)) - 1894007588
                            } else {
                                v += (r ^ q ^ p) - 899497514
                            }
                        }
                    }
                    m = p;
                    p = q;
                    q = (r << 30) | (r >>> 2);
                    r = s;
                    s = v
                }
                u[0] = (u[0] + s) | 0;
                u[1] = (u[1] + r) | 0;
                u[2] = (u[2] + q) | 0;
                u[3] = (u[3] + p) | 0;
                u[4] = (u[4] + m) | 0
            },
            _doFinalize: function() {
                var k = this._data;
                var l = k.words;
                var i = this._nDataBytes * 8;
                var j = k.sigBytes * 8;
                l[j >>> 5] |= 128 << (24 - j % 32);
                l[(((j + 64) >>> 9) << 4) + 14] = Math.floor(i / 4294967296);
                l[(((j + 64) >>> 9) << 4) + 15] = i;
                k.sigBytes = l.length * 4;
                this._process();
                return this._hash
            },
            clone: function() {
                var i = c.clone.call(this);
                i._hash = this._hash.clone();
                return i
            }
        });
        h.SHA1 = c._createHelper(d);
        h.HmacSHA1 = c._createHmacHelper(d)
    } ()); (function(d) {
        var b = a;
        var c = b.lib;
        var h = c.WordArray;
        var f = c.Hasher;
        var i = b.algo;
        var k = [];
        var j = []; (function() {
            function o(s) {
                var r = d.sqrt(s);
                for (var q = 2; q <= r; q++) {
                    if (! (s % q)) {
                        return false
                    }
                }
                return true
            }
            function m(q) {
                return ((q - (q | 0)) * 4294967296) | 0
            }
            var p = 2;
            var l = 0;
            while (l < 64) {
                if (o(p)) {
                    if (l < 8) {
                        k[l] = m(d.pow(p, 1 / 2))
                    }
                    j[l] = m(d.pow(p, 1 / 3));
                    l++
                }
                p++
            }
        } ());
        var e = [];
        var g = i.SHA256 = f.extend({
            _doReset: function() {
                this._hash = new h.init(k.slice(0))
            },
            _doProcessBlock: function(o, n) {
                var r = this._hash.words;
                var E = r[0];
                var D = r[1];
                var C = r[2];
                var B = r[3];
                var A = r[4];
                var z = r[5];
                var y = r[6];
                var x = r[7];
                for (var w = 0; w < 64; w++) {
                    if (w < 16) {
                        e[w] = o[n + w] | 0
                    } else {
                        var m = e[w - 15];
                        var G = ((m << 25) | (m >>> 7)) ^ ((m << 14) | (m >>> 18)) ^ (m >>> 3);
                        var s = e[w - 2];
                        var F = ((s << 15) | (s >>> 17)) ^ ((s << 13) | (s >>> 19)) ^ (s >>> 10);
                        e[w] = G + e[w - 7] + F + e[w - 16]
                    }
                    var t = (A & z) ^ (~A & y);
                    var l = (E & D) ^ (E & C) ^ (D & C);
                    var v = ((E << 30) | (E >>> 2)) ^ ((E << 19) | (E >>> 13)) ^ ((E << 10) | (E >>> 22));
                    var u = ((A << 26) | (A >>> 6)) ^ ((A << 21) | (A >>> 11)) ^ ((A << 7) | (A >>> 25));
                    var q = x + u + t + j[w] + e[w];
                    var p = v + l;
                    x = y;
                    y = z;
                    z = A;
                    A = (B + q) | 0;
                    B = C;
                    C = D;
                    D = E;
                    E = (q + p) | 0
                }
                r[0] = (r[0] + E) | 0;
                r[1] = (r[1] + D) | 0;
                r[2] = (r[2] + C) | 0;
                r[3] = (r[3] + B) | 0;
                r[4] = (r[4] + A) | 0;
                r[5] = (r[5] + z) | 0;
                r[6] = (r[6] + y) | 0;
                r[7] = (r[7] + x) | 0
            },
            _doFinalize: function() {
                var n = this._data;
                var o = n.words;
                var l = this._nDataBytes * 8;
                var m = n.sigBytes * 8;
                o[m >>> 5] |= 128 << (24 - m % 32);
                o[(((m + 64) >>> 9) << 4) + 14] = d.floor(l / 4294967296);
                o[(((m + 64) >>> 9) << 4) + 15] = l;
                n.sigBytes = o.length * 4;
                this._process();
                return this._hash
            },
            clone: function() {
                var l = f.clone.call(this);
                l._hash = this._hash.clone();
                return l
            }
        });
        b.SHA256 = f._createHelper(g);
        b.HmacSHA256 = f._createHmacHelper(g)
    } (Math)); (function() {
        var g = a;
        var b = g.lib;
        var d = b.WordArray;
        var f = g.enc;
        var e = f.Utf16 = f.Utf16BE = {
            stringify: function(l) {
                var n = l.words;
                var k = l.sigBytes;
                var m = [];
                for (var j = 0; j < k; j += 2) {
                    var h = (n[j >>> 2] >>> (16 - (j % 4) * 8)) & 65535;
                    m.push(String.fromCharCode(h))
                }
                return m.join("")
            },
            parse: function(h) {
                var k = h.length;
                var l = [];
                for (var j = 0; j < k; j++) {
                    l[j >>> 1] |= h.charCodeAt(j) << (16 - (j % 2) * 16)
                }
                return d.create(l, k * 2)
            }
        };
        f.Utf16LE = {
            stringify: function(l) {
                var n = l.words;
                var k = l.sigBytes;
                var m = [];
                for (var j = 0; j < k; j += 2) {
                    var h = c((n[j >>> 2] >>> (16 - (j % 4) * 8)) & 65535);
                    m.push(String.fromCharCode(h))
                }
                return m.join("")
            },
            parse: function(h) {
                var k = h.length;
                var l = [];
                for (var j = 0; j < k; j++) {
                    l[j >>> 1] |= c(h.charCodeAt(j) << (16 - (j % 2) * 16))
                }
                return d.create(l, k * 2)
            }
        };
        function c(h) {
            return ((h << 8) & 4278255360) | ((h >>> 8) & 16711935)
        }
    } ()); (function() {
        if (typeof ArrayBuffer != "function") {
            return
        }
        var f = a;
        var d = f.lib;
        var e = d.WordArray;
        var c = e.init;
        var b = e.init = function(j) {
            if (j instanceof ArrayBuffer) {
                j = new Uint8Array(j)
            }
            if (j instanceof Int8Array || (typeof Uint8ClampedArray !== "undefined" && j instanceof Uint8ClampedArray) || j instanceof Int16Array || j instanceof Uint16Array || j instanceof Int32Array || j instanceof Uint32Array || j instanceof Float32Array || j instanceof Float64Array) {
                j = new Uint8Array(j.buffer, j.byteOffset, j.byteLength)
            }
            if (j instanceof Uint8Array) {
                var g = j.byteLength;
                var k = [];
                for (var h = 0; h < g; h++) {
                    k[h >>> 2] |= j[h] << (24 - (h % 4) * 8)
                }
                c.call(this, k, g)
            } else {
                c.apply(this, arguments)
            }
        };
        b.prototype = e
    } ()); (function(g) {
        var j = a;
        var t = j.lib;
        var r = t.WordArray;
        var d = t.Hasher;
        var b = j.algo;
        var s = r.create([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8, 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12, 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2, 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13]);
        var p = r.create([5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12, 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2, 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13, 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14, 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11]);
        var f = r.create([11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8, 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12, 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5, 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12, 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6]);
        var e = r.create([8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6, 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11, 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5, 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8, 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11]);
        var n = r.create([0, 1518500249, 1859775393, 2400959708, 2840853838]);
        var h = r.create([1352829926, 1548603684, 1836072691, 2053994217, 0]);
        var c = b.RIPEMD160 = d.extend({
            _doReset: function() {
                this._hash = r.create([1732584193, 4023233417, 2562383102, 271733878, 3285377520])
            },
            _doProcessBlock: function(D, B) {
                for (var O = 0; O < 16; O++) {
                    var w = B + O;
                    var C = D[w];
                    D[w] = ((((C << 8) | (C >>> 24)) & 16711935) | (((C << 24) | (C >>> 8)) & 4278255360))
                }
                var F = this._hash.words;
                var y = n.words;
                var S = h.words;
                var z = s.words;
                var x = p.words;
                var P = f.words;
                var L = e.words;
                var K, u, E, N, v;
                var I, Q, A, J, R;
                I = K = F[0];
                Q = u = F[1];
                A = E = F[2];
                J = N = F[3];
                R = v = F[4];
                var G;
                for (var O = 0; O < 80; O += 1) {
                    G = (K + D[B + z[O]]) | 0;
                    if (O < 16) {
                        G += q(u, E, N) + y[0]
                    } else {
                        if (O < 32) {
                            G += o(u, E, N) + y[1]
                        } else {
                            if (O < 48) {
                                G += m(u, E, N) + y[2]
                            } else {
                                if (O < 64) {
                                    G += l(u, E, N) + y[3]
                                } else {
                                    G += k(u, E, N) + y[4]
                                }
                            }
                        }
                    }
                    G = G | 0;
                    G = i(G, P[O]);
                    G = (G + v) | 0;
                    K = v;
                    v = N;
                    N = i(E, 10);
                    E = u;
                    u = G;
                    G = (I + D[B + x[O]]) | 0;
                    if (O < 16) {
                        G += k(Q, A, J) + S[0]
                    } else {
                        if (O < 32) {
                            G += l(Q, A, J) + S[1]
                        } else {
                            if (O < 48) {
                                G += m(Q, A, J) + S[2]
                            } else {
                                if (O < 64) {
                                    G += o(Q, A, J) + S[3]
                                } else {
                                    G += q(Q, A, J) + S[4]
                                }
                            }
                        }
                    }
                    G = G | 0;
                    G = i(G, L[O]);
                    G = (G + R) | 0;
                    I = R;
                    R = J;
                    J = i(A, 10);
                    A = Q;
                    Q = G
                }
                G = (F[1] + E + J) | 0;
                F[1] = (F[2] + N + R) | 0;
                F[2] = (F[3] + v + I) | 0;
                F[3] = (F[4] + K + Q) | 0;
                F[4] = (F[0] + u + A) | 0;
                F[0] = G
            },
            _doFinalize: function() {
                var z = this._data;
                var B = z.words;
                var u = this._nDataBytes * 8;
                var y = z.sigBytes * 8;
                B[y >>> 5] |= 128 << (24 - y % 32);
                B[(((y + 64) >>> 9) << 4) + 14] = ((((u << 8) | (u >>> 24)) & 16711935) | (((u << 24) | (u >>> 8)) & 4278255360));
                z.sigBytes = (B.length + 1) * 4;
                this._process();
                var A = this._hash;
                var w = A.words;
                for (var v = 0; v < 5; v++) {
                    var x = w[v];
                    w[v] = (((x << 8) | (x >>> 24)) & 16711935) | (((x << 24) | (x >>> 8)) & 4278255360)
                }
                return A
            },
            clone: function() {
                var u = d.clone.call(this);
                u._hash = this._hash.clone();
                return u
            }
        });
        function q(u, w, v) {
            return ((u) ^ (w) ^ (v))
        }
        function o(u, w, v) {
            return (((u) & (w)) | ((~u) & (v)))
        }
        function m(u, w, v) {
            return (((u) | (~ (w))) ^ (v))
        }
        function l(u, w, v) {
            return (((u) & (v)) | ((w) & (~ (v))))
        }
        function k(u, w, v) {
            return ((u) ^ ((w) | (~ (v))))
        }
        function i(u, v) {
            return (u << v) | (u >>> (32 - v))
        }
        j.RIPEMD160 = d._createHelper(c);
        j.HmacRIPEMD160 = d._createHmacHelper(c)
    } (Math)); (function() {
        var h = a;
        var e = h.lib;
        var d = e.Base;
        var g = h.enc;
        var c = g.Utf8;
        var f = h.algo;
        var b = f.HMAC = d.extend({
            init: function(r, o) {
                r = this._hasher = new r.init();
                if (typeof o == "string") {
                    o = c.parse(o)
                }
                var l = r.blockSize;
                var j = l * 4;
                if (o.sigBytes > j) {
                    o = r.finalize(o)
                }
                o.clamp();
                var q = this._oKey = o.clone();
                var n = this._iKey = o.clone();
                var p = q.words;
                var k = n.words;
                for (var m = 0; m < l; m++) {
                    p[m] ^= 1549556828;
                    k[m] ^= 909522486
                }
                q.sigBytes = n.sigBytes = j;
                this.reset()
            },
            reset: function() {
                var i = this._hasher;
                i.reset();
                i.update(this._iKey)
            },
            update: function(i) {
                this._hasher.update(i);
                return this
            },
            finalize: function(i) {
                var j = this._hasher;
                var l = j.finalize(i);
                j.reset();
                var k = j.finalize(this._oKey.clone().concat(l));
                return k
            }
        })
    } ()); (function() {
        var i = a;
        var e = i.lib;
        var c = e.Base;
        var g = e.WordArray;
        var f = i.algo;
        var d = f.SHA1;
        var b = f.HMAC;
        var h = f.PBKDF2 = c.extend({
            cfg: c.extend({
                keySize: 128 / 32,
                hasher: d,
                iterations: 1
            }),
            init: function(j) {
                this.cfg = this.cfg.extend(j)
            },
            compute: function(z, s) {
                var v = this.cfg;
                var t = b.create(v.hasher, z);
                var u = g.create();
                var A = g.create([1]);
                var x = u.words;
                var m = A.words;
                var w = v.keySize;
                var l = v.iterations;
                while (x.length < w) {
                    var n = t.update(s).finalize(A);
                    t.reset();
                    var k = n.words;
                    var y = k.length;
                    var p = n;
                    for (var r = 1; r < l; r++) {
                        p = t.finalize(p);
                        t.reset();
                        var q = p.words;
                        for (var o = 0; o < y; o++) {
                            k[o] ^= q[o]
                        }
                    }
                    u.concat(n);
                    m[0]++
                }
                u.sigBytes = w * 4;
                return u
            }
        });
        i.PBKDF2 = function(k, l, j) {
            return h.create(j).compute(k, l)
        }
    } ()); (function() {
        var h = a;
        var e = h.lib;
        var c = e.Base;
        var g = e.WordArray;
        var f = h.algo;
        var d = f.MD5;
        var b = f.EvpKDF = c.extend({
            cfg: c.extend({
                keySize: 128 / 32,
                hasher: d,
                iterations: 1
            }),
            init: function(i) {
                this.cfg = this.cfg.extend(i)
            },
            compute: function(r, m) {
                var o = this.cfg;
                var s = o.hasher.create();
                var n = g.create();
                var q = n.words;
                var p = o.keySize;
                var j = o.iterations;
                while (q.length < p) {
                    if (k) {
                        s.update(k)
                    }
                    var k = s.update(r).finalize(m);
                    s.reset();
                    for (var l = 1; l < j; l++) {
                        k = s.finalize(k);
                        s.reset()
                    }
                    n.concat(k)
                }
                n.sigBytes = p * 4;
                return n
            }
        });
        h.EvpKDF = function(j, k, i) {
            return b.create(i).compute(j, k)
        }
    } ()); (function() {
        var g = a;
        var c = g.lib;
        var f = c.WordArray;
        var d = g.algo;
        var e = d.SHA256;
        var b = d.SHA224 = e.extend({
            _doReset: function() {
                this._hash = new f.init([3238371032, 914150663, 812702999, 4144912697, 4290775857, 1750603025, 1694076839, 3204075428])
            },
            _doFinalize: function() {
                var h = e._doFinalize.call(this);
                h.sigBytes -= 4;
                return h
            }
        });
        g.SHA224 = e._createHelper(b);
        g.HmacSHA224 = e._createHmacHelper(b)
    } ()); (function(i) {
        var h = a;
        var d = h.lib;
        var c = d.Base;
        var g = d.WordArray;
        var b = h.x64 = {};
        var e = b.Word = c.extend({
            init: function(k, j) {
                this.high = k;
                this.low = j
            }
        });
        var f = b.WordArray = c.extend({
            init: function(k, j) {
                k = this.words = k || [];
                if (j != i) {
                    this.sigBytes = j
                } else {
                    this.sigBytes = k.length * 8
                }
            },
            toX32: function() {
                var l = this.words;
                var k = l.length;
                var n = [];
                for (var j = 0; j < k; j++) {
                    var m = l[j];
                    n.push(m.high);
                    n.push(m.low)
                }
                return g.create(n, this.sigBytes)
            },
            clone: function() {
                var m = c.clone.call(this);
                var l = m.words = this.words.slice(0);
                var k = l.length;
                for (var j = 0; j < k; j++) {
                    l[j] = l[j].clone()
                }
                return m
            }
        })
    } ()); (function(e) {
        var c = a;
        var d = c.lib;
        var m = d.WordArray;
        var h = d.Hasher;
        var j = c.x64;
        var g = j.Word;
        var n = c.algo;
        var b = [];
        var k = [];
        var l = []; (function() {
            var v = 1,
            u = 0;
            for (var z = 0; z < 24; z++) {
                b[v + 5 * u] = ((z + 1) * (z + 2) / 2) % 64;
                var o = u % 5;
                var B = (2 * v + 3 * u) % 5;
                v = o;
                u = B
            }
            for (var v = 0; v < 5; v++) {
                for (var u = 0; u < 5; u++) {
                    k[v + 5 * u] = u + ((2 * v + 3 * u) % 5) * 5
                }
            }
            var A = 1;
            for (var r = 0; r < 24; r++) {
                var s = 0;
                var p = 0;
                for (var q = 0; q < 7; q++) {
                    if (A & 1) {
                        var w = (1 << q) - 1;
                        if (w < 32) {
                            p ^= 1 << w
                        } else {
                            s ^= 1 << (w - 32)
                        }
                    }
                    if (A & 128) {
                        A = (A << 1) ^ 113
                    } else {
                        A <<= 1
                    }
                }
                l[r] = g.create(s, p)
            }
        } ());
        var i = []; (function() {
            for (var o = 0; o < 25; o++) {
                i[o] = g.create()
            }
        } ());
        var f = n.SHA3 = h.extend({
            cfg: h.cfg.extend({
                outputLength: 512
            }),
            _doReset: function() {
                var p = this._state = [];
                for (var o = 0; o < 25; o++) {
                    p[o] = new g.init()
                }
                this.blockSize = (1600 - 2 * this.cfg.outputLength) / 32
            },
            _doProcessBlock: function(D, z) {
                var w = this._state;
                var r = this.blockSize / 2;
                for (var O = 0; O < r; O++) {
                    var E = D[z + 2 * O];
                    var Q = D[z + 2 * O + 1];
                    E = ((((E << 8) | (E >>> 24)) & 16711935) | (((E << 24) | (E >>> 8)) & 4278255360));
                    Q = ((((Q << 8) | (Q >>> 24)) & 16711935) | (((Q << 24) | (Q >>> 8)) & 4278255360));
                    var q = w[O];
                    q.high ^= Q;
                    q.low ^= E
                }
                for (var R = 0; R < 24; R++) {
                    for (var H = 0; H < 5; H++) {
                        var J = 0,
                        S = 0;
                        for (var G = 0; G < 5; G++) {
                            var q = w[H + 5 * G];
                            J ^= q.high;
                            S ^= q.low
                        }
                        var p = i[H];
                        p.high = J;
                        p.low = S
                    }
                    for (var H = 0; H < 5; H++) {
                        var v = i[(H + 4) % 5];
                        var A = i[(H + 1) % 5];
                        var N = A.high;
                        var t = A.low;
                        var J = v.high ^ ((N << 1) | (t >>> 31));
                        var S = v.low ^ ((t << 1) | (N >>> 31));
                        for (var G = 0; G < 5; G++) {
                            var q = w[H + 5 * G];
                            q.high ^= J;
                            q.low ^= S
                        }
                    }
                    for (var u = 1; u < 25; u++) {
                        var q = w[u];
                        var o = q.high;
                        var I = q.low;
                        var P = b[u];
                        if (P < 32) {
                            var J = (o << P) | (I >>> (32 - P));
                            var S = (I << P) | (o >>> (32 - P))
                        } else {
                            var J = (I << (P - 32)) | (o >>> (64 - P));
                            var S = (o << (P - 32)) | (I >>> (64 - P))
                        }
                        var C = i[k[u]];
                        C.high = J;
                        C.low = S
                    }
                    var K = i[0];
                    var L = w[0];
                    K.high = L.high;
                    K.low = L.low;
                    for (var H = 0; H < 5; H++) {
                        for (var G = 0; G < 5; G++) {
                            var u = H + 5 * G;
                            var q = w[u];
                            var s = i[u];
                            var B = i[((H + 1) % 5) + 5 * G];
                            var T = i[((H + 2) % 5) + 5 * G];
                            q.high = s.high ^ (~B.high & T.high);
                            q.low = s.low ^ (~B.low & T.low)
                        }
                    }
                    var q = w[0];
                    var F = l[R];
                    q.high ^= F.high;
                    q.low ^= F.low
                }
            },
            _doFinalize: function() {
                var t = this._data;
                var A = t.words;
                var w = this._nDataBytes * 8;
                var x = t.sigBytes * 8;
                var z = this.blockSize * 32;
                A[x >>> 5] |= 1 << (24 - x % 32);
                A[((e.ceil((x + 1) / z) * z) >>> 5) - 1] |= 128;
                t.sigBytes = A.length * 4;
                this._process();
                var o = this._state;
                var q = this.cfg.outputLength / 8;
                var u = q / 8;
                var s = [];
                for (var r = 0; r < u; r++) {
                    var p = o[r];
                    var y = p.high;
                    var v = p.low;
                    y = ((((y << 8) | (y >>> 24)) & 16711935) | (((y << 24) | (y >>> 8)) & 4278255360));
                    v = ((((v << 8) | (v >>> 24)) & 16711935) | (((v << 24) | (v >>> 8)) & 4278255360));
                    s.push(v);
                    s.push(y)
                }
                return new m.init(s, q)
            },
            clone: function() {
                var q = h.clone.call(this);
                var p = q._state = this._state.slice(0);
                for (var o = 0; o < 25; o++) {
                    p[o] = p[o].clone()
                }
                return q
            }
        });
        c.SHA3 = h._createHelper(f);
        c.HmacSHA3 = h._createHmacHelper(f)
    } (Math)); (function() {
        var b = a;
        var c = b.lib;
        var f = c.Hasher;
        var g = b.x64;
        var e = g.Word;
        var k = g.WordArray;
        var j = b.algo;
        function h() {
            return e.create.apply(e, arguments)
        }
        var l = [h(1116352408, 3609767458), h(1899447441, 602891725), h(3049323471, 3964484399), h(3921009573, 2173295548), h(961987163, 4081628472), h(1508970993, 3053834265), h(2453635748, 2937671579), h(2870763221, 3664609560), h(3624381080, 2734883394), h(310598401, 1164996542), h(607225278, 1323610764), h(1426881987, 3590304994), h(1925078388, 4068182383), h(2162078206, 991336113), h(2614888103, 633803317), h(3248222580, 3479774868), h(3835390401, 2666613458), h(4022224774, 944711139), h(264347078, 2341262773), h(604807628, 2007800933), h(770255983, 1495990901), h(1249150122, 1856431235), h(1555081692, 3175218132), h(1996064986, 2198950837), h(2554220882, 3999719339), h(2821834349, 766784016), h(2952996808, 2566594879), h(3210313671, 3203337956), h(3336571891, 1034457026), h(3584528711, 2466948901), h(113926993, 3758326383), h(338241895, 168717936), h(666307205, 1188179964), h(773529912, 1546045734), h(1294757372, 1522805485), h(1396182291, 2643833823), h(1695183700, 2343527390), h(1986661051, 1014477480), h(2177026350, 1206759142), h(2456956037, 344077627), h(2730485921, 1290863460), h(2820302411, 3158454273), h(3259730800, 3505952657), h(3345764771, 106217008), h(3516065817, 3606008344), h(3600352804, 1432725776), h(4094571909, 1467031594), h(275423344, 851169720), h(430227734, 3100823752), h(506948616, 1363258195), h(659060556, 3750685593), h(883997877, 3785050280), h(958139571, 3318307427), h(1322822218, 3812723403), h(1537002063, 2003034995), h(1747873779, 3602036899), h(1955562222, 1575990012), h(2024104815, 1125592928), h(2227730452, 2716904306), h(2361852424, 442776044), h(2428436474, 593698344), h(2756734187, 3733110249), h(3204031479, 2999351573), h(3329325298, 3815920427), h(3391569614, 3928383900), h(3515267271, 566280711), h(3940187606, 3454069534), h(4118630271, 4000239992), h(116418474, 1914138554), h(174292421, 2731055270), h(289380356, 3203993006), h(460393269, 320620315), h(685471733, 587496836), h(852142971, 1086792851), h(1017036298, 365543100), h(1126000580, 2618297676), h(1288033470, 3409855158), h(1501505948, 4234509866), h(1607167915, 987167468), h(1816402316, 1246189591)];
        var d = []; (function() {
            for (var m = 0; m < 80; m++) {
                d[m] = h()
            }
        } ());
        var i = j.SHA512 = f.extend({
            _doReset: function() {
                this._hash = new k.init([new e.init(1779033703, 4089235720), new e.init(3144134277, 2227873595), new e.init(1013904242, 4271175723), new e.init(2773480762, 1595750129), new e.init(1359893119, 2917565137), new e.init(2600822924, 725511199), new e.init(528734635, 4215389547), new e.init(1541459225, 327033209)])
            },
            _doProcessBlock: function(ap, D) {
                var aq = this._hash.words;
                var z = aq[0];
                var w = aq[1];
                var u = aq[2];
                var t = aq[3];
                var r = aq[4];
                var p = aq[5];
                var n = aq[6];
                var m = aq[7];
                var U = z.high;
                var S = z.low;
                var L = w.high;
                var J = w.low;
                var B = u.high;
                var y = u.low;
                var aN = t.high;
                var aL = t.low;
                var aF = r.high;
                var aC = r.low;
                var ao = p.high;
                var am = p.low;
                var W = n.high;
                var V = n.low;
                var O = m.high;
                var N = m.low;
                var az = U;
                var aw = S;
                var ai = L;
                var af = J;
                var T = B;
                var R = y;
                var K = aN;
                var I = aL;
                var A = aF;
                var s = aC;
                var aM = ao;
                var aK = am;
                var aD = W;
                var aA = V;
                var an = O;
                var aj = N;
                for (var Y = 0; Y < 80; Y++) {
                    var Q = d[Y];
                    if (Y < 16) {
                        var av = Q.high = ap[D + Y * 2] | 0;
                        var at = Q.low = ap[D + Y * 2 + 1] | 0
                    } else {
                        var ar = d[Y - 15];
                        var G = ar.high;
                        var F = ar.low;
                        var aB = ((G >>> 1) | (F << 31)) ^ ((G >>> 8) | (F << 24)) ^ (G >>> 7);
                        var ay = ((F >>> 1) | (G << 31)) ^ ((F >>> 8) | (G << 24)) ^ ((F >>> 7) | (G << 25));
                        var ab = d[Y - 2];
                        var E = ab.high;
                        var C = ab.low;
                        var ak = ((E >>> 19) | (C << 13)) ^ ((E << 3) | (C >>> 29)) ^ (E >>> 6);
                        var ag = ((C >>> 19) | (E << 13)) ^ ((C << 3) | (E >>> 29)) ^ ((C >>> 6) | (E << 26));
                        var aO = d[Y - 7];
                        var ae = aO.high;
                        var ac = aO.low;
                        var aE = d[Y - 16];
                        var ad = aE.high;
                        var aa = aE.low;
                        var at = ay + ac;
                        var av = aB + ae + ((at >>> 0) < (ay >>> 0) ? 1 : 0);
                        var at = at + ag;
                        var av = av + ak + ((at >>> 0) < (ag >>> 0) ? 1 : 0);
                        var at = at + aa;
                        var av = av + ad + ((at >>> 0) < (aa >>> 0) ? 1 : 0);
                        Q.high = av;
                        Q.low = at
                    }
                    var Z = (A & aM) ^ (~A & aD);
                    var X = (s & aK) ^ (~s & aA);
                    var x = (az & ai) ^ (az & T) ^ (ai & T);
                    var q = (aw & af) ^ (aw & R) ^ (af & R);
                    var aQ = ((az >>> 28) | (aw << 4)) ^ ((az << 30) | (aw >>> 2)) ^ ((az << 25) | (aw >>> 7));
                    var aP = ((aw >>> 28) | (az << 4)) ^ ((aw << 30) | (az >>> 2)) ^ ((aw << 25) | (az >>> 7));
                    var aH = ((A >>> 14) | (s << 18)) ^ ((A >>> 18) | (s << 14)) ^ ((A << 23) | (s >>> 9));
                    var aG = ((s >>> 14) | (A << 18)) ^ ((s >>> 18) | (A << 14)) ^ ((s << 23) | (A >>> 9));
                    var P = l[Y];
                    var v = P.high;
                    var o = P.low;
                    var aI = aj + aG;
                    var aJ = an + aH + ((aI >>> 0) < (aj >>> 0) ? 1 : 0);
                    var aI = aI + X;
                    var aJ = aJ + Z + ((aI >>> 0) < (X >>> 0) ? 1 : 0);
                    var aI = aI + o;
                    var aJ = aJ + v + ((aI >>> 0) < (o >>> 0) ? 1 : 0);
                    var aI = aI + at;
                    var aJ = aJ + av + ((aI >>> 0) < (at >>> 0) ? 1 : 0);
                    var au = aP + q;
                    var ax = aQ + x + ((au >>> 0) < (aP >>> 0) ? 1 : 0);
                    an = aD;
                    aj = aA;
                    aD = aM;
                    aA = aK;
                    aM = A;
                    aK = s;
                    s = (I + aI) | 0;
                    A = (K + aJ + ((s >>> 0) < (I >>> 0) ? 1 : 0)) | 0;
                    K = T;
                    I = R;
                    T = ai;
                    R = af;
                    ai = az;
                    af = aw;
                    aw = (aI + au) | 0;
                    az = (aJ + ax + ((aw >>> 0) < (aI >>> 0) ? 1 : 0)) | 0
                }
                S = z.low = (S + aw);
                z.high = (U + az + ((S >>> 0) < (aw >>> 0) ? 1 : 0));
                J = w.low = (J + af);
                w.high = (L + ai + ((J >>> 0) < (af >>> 0) ? 1 : 0));
                y = u.low = (y + R);
                u.high = (B + T + ((y >>> 0) < (R >>> 0) ? 1 : 0));
                aL = t.low = (aL + I);
                t.high = (aN + K + ((aL >>> 0) < (I >>> 0) ? 1 : 0));
                aC = r.low = (aC + s);
                r.high = (aF + A + ((aC >>> 0) < (s >>> 0) ? 1 : 0));
                am = p.low = (am + aK);
                p.high = (ao + aM + ((am >>> 0) < (aK >>> 0) ? 1 : 0));
                V = n.low = (V + aA);
                n.high = (W + aD + ((V >>> 0) < (aA >>> 0) ? 1 : 0));
                N = m.low = (N + aj);
                m.high = (O + an + ((N >>> 0) < (aj >>> 0) ? 1 : 0))
            },
            _doFinalize: function() {
                var o = this._data;
                var q = o.words;
                var m = this._nDataBytes * 8;
                var n = o.sigBytes * 8;
                q[n >>> 5] |= 128 << (24 - n % 32);
                q[(((n + 128) >>> 10) << 5) + 30] = Math.floor(m / 4294967296);
                q[(((n + 128) >>> 10) << 5) + 31] = m;
                o.sigBytes = q.length * 4;
                this._process();
                var p = this._hash.toX32();
                return p
            },
            clone: function() {
                var m = f.clone.call(this);
                m._hash = this._hash.clone();
                return m
            },
            blockSize: 1024 / 32
        });
        b.SHA512 = f._createHelper(i);
        b.HmacSHA512 = f._createHmacHelper(i)
    } ()); (function() {
        var h = a;
        var c = h.x64;
        var f = c.Word;
        var g = c.WordArray;
        var e = h.algo;
        var d = e.SHA512;
        var b = e.SHA384 = d.extend({
            _doReset: function() {
                this._hash = new g.init([new f.init(3418070365, 3238371032), new f.init(1654270250, 914150663), new f.init(2438529370, 812702999), new f.init(355462360, 4144912697), new f.init(1731405415, 4290775857), new f.init(2394180231, 1750603025), new f.init(3675008525, 1694076839), new f.init(1203062813, 3204075428)])
            },
            _doFinalize: function() {
                var i = d._doFinalize.call(this);
                i.sigBytes -= 16;
                return i
            }
        });
        h.SHA384 = d._createHelper(b);
        h.HmacSHA384 = d._createHmacHelper(b)
    } ());
    a.lib.Cipher || (function(e) {
        var n = a;
        var x = n.lib;
        var j = x.Base;
        var u = x.WordArray;
        var w = x.BufferedBlockAlgorithm;
        var s = n.enc;
        var g = s.Utf8;
        var m = s.Base64;
        var c = n.algo;
        var i = c.EvpKDF;
        var k = x.Cipher = w.extend({
            cfg: j.extend(),
            createEncryptor: function(C, B) {
                return this.create(this._ENC_XFORM_MODE, C, B)
            },
            createDecryptor: function(C, B) {
                return this.create(this._DEC_XFORM_MODE, C, B)
            },
            init: function(D, C, B) {
                this.cfg = this.cfg.extend(B);
                this._xformMode = D;
                this._key = C;
                this.reset()
            },
            reset: function() {
                w.reset.call(this);
                this._doReset()
            },
            process: function(B) {
                this._append(B);
                return this._process()
            },
            finalize: function(C) {
                if (C) {
                    this._append(C)
                }
                var B = this._doFinalize();
                return B
            },
            keySize: 128 / 32,
            ivSize: 128 / 32,
            _ENC_XFORM_MODE: 1,
            _DEC_XFORM_MODE: 2,
            _createHelper: (function() {
                function B(C) {
                    if (typeof C == "string") {
                        return h
                    } else {
                        return A
                    }
                }
                return function(C) {
                    return {
                        encrypt: function(F, E, D) {
                            return B(E).encrypt(C, F, E, D)
                        },
                        decrypt: function(F, E, D) {
                            return B(E).decrypt(C, F, E, D)
                        }
                    }
                }
            } ())
        });
        var q = x.StreamCipher = k.extend({
            _doFinalize: function() {
                var B = this._process( !! "flush");
                return B
            },
            blockSize: 1
        });
        var t = n.mode = {};
        var z = x.BlockCipherMode = j.extend({
            createEncryptor: function(B, C) {
                return this.Encryptor.create(B, C)
            },
            createDecryptor: function(B, C) {
                return this.Decryptor.create(B, C)
            },
            init: function(B, C) {
                this._cipher = B;
                this._iv = C
            }
        });
        var d = t.CBC = (function() {
            var B = z.extend();
            B.Encryptor = B.extend({
                processBlock: function(G, F) {
                    var D = this._cipher;
                    var E = D.blockSize;
                    C.call(this, G, F, E);
                    D.encryptBlock(G, F);
                    this._prevBlock = G.slice(F, F + E)
                }
            });
            B.Decryptor = B.extend({
                processBlock: function(H, G) {
                    var D = this._cipher;
                    var F = D.blockSize;
                    var E = H.slice(G, G + F);
                    D.decryptBlock(H, G);
                    C.call(this, H, G, F);
                    this._prevBlock = E
                }
            });
            function C(I, H, F) {
                var D = this._iv;
                if (D) {
                    var G = D;
                    this._iv = e
                } else {
                    var G = this._prevBlock
                }
                for (var E = 0; E < F; E++) {
                    I[H + E] ^= G[E]
                }
            }
            return B
        } ());
        var f = n.pad = {};
        var b = f.Pkcs7 = {
            pad: function(G, E) {
                var F = E * 4;
                var I = F - G.sigBytes % F;
                var B = (I << 24) | (I << 16) | (I << 8) | I;
                var D = [];
                for (var C = 0; C < I; C += 4) {
                    D.push(B)
                }
                var H = u.create(D, I);
                G.concat(H)
            },
            unpad: function(B) {
                var C = B.words[(B.sigBytes - 1) >>> 2] & 255;
                B.sigBytes -= C
            }
        };
        var r = x.BlockCipher = k.extend({
            cfg: k.cfg.extend({
                mode: d,
                padding: b
            }),
            reset: function() {
                k.reset.call(this);
                var B = this.cfg;
                var C = B.iv;
                var E = B.mode;
                if (this._xformMode == this._ENC_XFORM_MODE) {
                    var D = E.createEncryptor
                } else {
                    var D = E.createDecryptor;
                    this._minBufferSize = 1
                }
                if (this._mode && this._mode.__creator == D) {
                    this._mode.init(this, C && C.words)
                } else {
                    this._mode = D.call(E, this, C && C.words);
                    this._mode.__creator = D
                }
            },
            _doProcessBlock: function(C, B) {
                this._mode.processBlock(C, B)
            },
            _doFinalize: function() {
                var C = this.cfg.padding;
                if (this._xformMode == this._ENC_XFORM_MODE) {
                    C.pad(this._data, this.blockSize);
                    var B = this._process( !! "flush")
                } else {
                    var B = this._process( !! "flush");
                    C.unpad(B)
                }
                return B
            },
            blockSize: 128 / 32
        });
        var p = x.CipherParams = j.extend({
            init: function(B) {
                this.mixIn(B)
            },
            toString: function(B) {
                return (B || this.formatter).stringify(this)
            }
        });
        var o = n.format = {};
        var v = o.OpenSSL = {
            stringify: function(B) {
                var E = B.ciphertext;
                var C = B.salt;
                if (C) {
                    var D = u.create([1398893684, 1701076831]).concat(C).concat(E)
                } else {
                    var D = E
                }
                return D.toString(m)
            },
            parse: function(D) {
                var C = m.parse(D);
                var E = C.words;
                if (E[0] == 1398893684 && E[1] == 1701076831) {
                    var B = u.create(E.slice(2, 4));
                    E.splice(0, 4);
                    C.sigBytes -= 16
                }
                return p.create({
                    ciphertext: C,
                    salt: B
                })
            }
        };
        var A = x.SerializableCipher = j.extend({
            cfg: j.extend({
                format: v
            }),
            encrypt: function(B, G, E, C) {
                C = this.cfg.extend(C);
                var D = B.createEncryptor(E, C);
                var H = D.finalize(G);
                var F = D.cfg;
                return p.create({
                    ciphertext: H,
                    key: E,
                    iv: F.iv,
                    algorithm: B,
                    mode: F.mode,
                    padding: F.padding,
                    blockSize: B.blockSize,
                    formatter: C.format
                })
            },
            decrypt: function(B, F, D, C) {
                C = this.cfg.extend(C);
                F = this._parse(F, C.format);
                var E = B.createDecryptor(D, C).finalize(F.ciphertext);
                return E
            },
            _parse: function(B, C) {
                if (typeof B == "string") {
                    return C.parse(B, this)
                } else {
                    return B
                }
            }
        });
        var l = n.kdf = {};
        var y = l.OpenSSL = {
            execute: function(D, G, B, F) {
                if (!F) {
                    F = u.random(64 / 8)
                }
                var E = i.create({
                    keySize: G + B
                }).compute(D, F);
                var C = u.create(E.words.slice(G), B * 4);
                E.sigBytes = G * 4;
                return p.create({
                    key: E,
                    iv: C,
                    salt: F
                })
            }
        };
        var h = x.PasswordBasedCipher = A.extend({
            cfg: A.cfg.extend({
                kdf: y
            }),
            encrypt: function(B, E, D, C) {
                C = this.cfg.extend(C);
                var G = C.kdf.execute(D, B.keySize, B.ivSize);
                C.iv = G.iv;
                var F = A.encrypt.call(this, B, E, G.key, C);
                F.mixIn(G);
                return F
            },
            decrypt: function(B, F, D, C) {
                C = this.cfg.extend(C);
                F = this._parse(F, C.format);
                var G = C.kdf.execute(D, B.keySize, B.ivSize, F.salt);
                C.iv = G.iv;
                var E = A.decrypt.call(this, B, F, G.key, C);
                return E
            }
        })
    } ());
    a.mode.CFB = (function() {
        var c = a.lib.BlockCipherMode.extend();
        c.Encryptor = c.extend({
            processBlock: function(g, f) {
                var d = this._cipher;
                var e = d.blockSize;
                b.call(this, g, f, e, d);
                this._prevBlock = g.slice(f, f + e)
            }
        });
        c.Decryptor = c.extend({
            processBlock: function(h, g) {
                var d = this._cipher;
                var f = d.blockSize;
                var e = h.slice(g, g + f);
                b.call(this, h, g, f, d);
                this._prevBlock = e
            }
        });
        function b(k, j, g, d) {
            var e = this._iv;
            if (e) {
                var h = e.slice(0);
                this._iv = undefined
            } else {
                var h = this._prevBlock
            }
            d.encryptBlock(h, 0);
            for (var f = 0; f < g; f++) {
                k[j + f] ^= h[f]
            }
        }
        return c
    } ());
    a.mode.ECB = (function() {
        var b = a.lib.BlockCipherMode.extend();
        b.Encryptor = b.extend({
            processBlock: function(d, c) {
                this._cipher.encryptBlock(d, c)
            }
        });
        b.Decryptor = b.extend({
            processBlock: function(d, c) {
                this._cipher.decryptBlock(d, c)
            }
        });
        return b
    } ());
    a.pad.AnsiX923 = {
        pad: function(e, c) {
            var g = e.sigBytes;
            var d = c * 4;
            var f = d - g % d;
            var b = g + f - 1;
            e.clamp();
            e.words[b >>> 2] |= f << (24 - (b % 4) * 8);
            e.sigBytes += f
        },
        unpad: function(b) {
            var c = b.words[(b.sigBytes - 1) >>> 2] & 255;
            b.sigBytes -= c
        }
    };
    a.pad.Iso10126 = {
        pad: function(d, b) {
            var c = b * 4;
            var e = c - d.sigBytes % c;
            d.concat(a.lib.WordArray.random(e - 1)).concat(a.lib.WordArray.create([e << 24], 1))
        },
        unpad: function(b) {
            var c = b.words[(b.sigBytes - 1) >>> 2] & 255;
            b.sigBytes -= c
        }
    };
    a.pad.Iso97971 = {
        pad: function(c, b) {
            c.concat(a.lib.WordArray.create([2147483648], 1));
            a.pad.ZeroPadding.pad(c, b)
        },
        unpad: function(b) {
            a.pad.ZeroPadding.unpad(b);
            b.sigBytes--
        }
    };
    a.mode.OFB = (function() {
        var c = a.lib.BlockCipherMode.extend();
        var b = c.Encryptor = c.extend({
            processBlock: function(k, j) {
                var d = this._cipher;
                var g = d.blockSize;
                var e = this._iv;
                var h = this._keystream;
                if (e) {
                    h = this._keystream = e.slice(0);
                    this._iv = undefined
                }
                d.encryptBlock(h, 0);
                for (var f = 0; f < g; f++) {
                    k[j + f] ^= h[f]
                }
            }
        });
        c.Decryptor = b;
        return c
    } ());
    a.pad.NoPadding = {
        pad: function() {},
        unpad: function() {}
    }; (function(h) {
        var g = a;
        var d = g.lib;
        var c = d.CipherParams;
        var f = g.enc;
        var b = f.Hex;
        var i = g.format;
        var e = i.Hex = {
            stringify: function(j) {
                return j.ciphertext.toString(b)
            },
            parse: function(j) {
                var k = b.parse(j);
                return c.create({
                    ciphertext: k
                })
            }
        }
    } ()); (function() {
        var b = a;
        var c = b.lib;
        var q = c.BlockCipher;
        var l = b.algo;
        var e = [];
        var m = [];
        var p = [];
        var o = [];
        var n = [];
        var k = [];
        var j = [];
        var i = [];
        var h = [];
        var g = []; (function() {
            var u = [];
            for (var s = 0; s < 256; s++) {
                if (s < 128) {
                    u[s] = s << 1
                } else {
                    u[s] = (s << 1) ^ 283
                }
            }
            var y = 0;
            var v = 0;
            for (var s = 0; s < 256; s++) {
                var w = v ^ (v << 1) ^ (v << 2) ^ (v << 3) ^ (v << 4);
                w = (w >>> 8) ^ (w & 255) ^ 99;
                e[y] = w;
                m[w] = y;
                var r = u[y];
                var B = u[r];
                var z = u[B];
                var A = (u[w] * 257) ^ (w * 16843008);
                p[y] = (A << 24) | (A >>> 8);
                o[y] = (A << 16) | (A >>> 16);
                n[y] = (A << 8) | (A >>> 24);
                k[y] = A;
                var A = (z * 16843009) ^ (B * 65537) ^ (r * 257) ^ (y * 16843008);
                j[w] = (A << 24) | (A >>> 8);
                i[w] = (A << 16) | (A >>> 16);
                h[w] = (A << 8) | (A >>> 24);
                g[w] = A;
                if (!y) {
                    y = v = 1
                } else {
                    y = r ^ u[u[u[z ^ r]]];
                    v ^= u[u[v]]
                }
            }
        } ());
        var d = [0, 1, 2, 4, 8, 16, 32, 64, 128, 27, 54];
        var f = l.AES = q.extend({
            _doReset: function() {
                if (this._nRounds && this._keyPriorReset === this._key) {
                    return
                }
                var A = this._keyPriorReset = this._key;
                var s = A.words;
                var z = A.sigBytes / 4;
                var y = this._nRounds = z + 6;
                var r = (y + 1) * 4;
                var u = this._keySchedule = [];
                for (var x = 0; x < r; x++) {
                    if (x < z) {
                        u[x] = s[x]
                    } else {
                        var B = u[x - 1];
                        if (! (x % z)) {
                            B = (B << 8) | (B >>> 24);
                            B = (e[B >>> 24] << 24) | (e[(B >>> 16) & 255] << 16) | (e[(B >>> 8) & 255] << 8) | e[B & 255];
                            B ^= d[(x / z) | 0] << 24
                        } else {
                            if (z > 6 && x % z == 4) {
                                B = (e[B >>> 24] << 24) | (e[(B >>> 16) & 255] << 16) | (e[(B >>> 8) & 255] << 8) | e[B & 255]
                            }
                        }
                        u[x] = u[x - z] ^ B
                    }
                }
                var v = this._invKeySchedule = [];
                for (var w = 0; w < r; w++) {
                    var x = r - w;
                    if (w % 4) {
                        var B = u[x]
                    } else {
                        var B = u[x - 4]
                    }
                    if (w < 4 || x <= 4) {
                        v[w] = B
                    } else {
                        v[w] = j[e[B >>> 24]] ^ i[e[(B >>> 16) & 255]] ^ h[e[(B >>> 8) & 255]] ^ g[e[B & 255]]
                    }
                }
            },
            encryptBlock: function(s, r) {
                this._doCryptBlock(s, r, this._keySchedule, p, o, n, k, e)
            },
            decryptBlock: function(u, s) {
                var r = u[s + 1];
                u[s + 1] = u[s + 3];
                u[s + 3] = r;
                this._doCryptBlock(u, s, this._invKeySchedule, j, i, h, g, m);
                var r = u[s + 1];
                u[s + 1] = u[s + 3];
                u[s + 3] = r
            },
            _doCryptBlock: function(A, z, I, w, u, s, r, H) {
                var F = this._nRounds;
                var y = A[z] ^ I[0];
                var x = A[z + 1] ^ I[1];
                var v = A[z + 2] ^ I[2];
                var t = A[z + 3] ^ I[3];
                var G = 4;
                for (var J = 1; J < F; J++) {
                    var E = w[y >>> 24] ^ u[(x >>> 16) & 255] ^ s[(v >>> 8) & 255] ^ r[t & 255] ^ I[G++];
                    var D = w[x >>> 24] ^ u[(v >>> 16) & 255] ^ s[(t >>> 8) & 255] ^ r[y & 255] ^ I[G++];
                    var C = w[v >>> 24] ^ u[(t >>> 16) & 255] ^ s[(y >>> 8) & 255] ^ r[x & 255] ^ I[G++];
                    var B = w[t >>> 24] ^ u[(y >>> 16) & 255] ^ s[(x >>> 8) & 255] ^ r[v & 255] ^ I[G++];
                    y = E;
                    x = D;
                    v = C;
                    t = B
                }
                var E = ((H[y >>> 24] << 24) | (H[(x >>> 16) & 255] << 16) | (H[(v >>> 8) & 255] << 8) | H[t & 255]) ^ I[G++];
                var D = ((H[x >>> 24] << 24) | (H[(v >>> 16) & 255] << 16) | (H[(t >>> 8) & 255] << 8) | H[y & 255]) ^ I[G++];
                var C = ((H[v >>> 24] << 24) | (H[(t >>> 16) & 255] << 16) | (H[(y >>> 8) & 255] << 8) | H[x & 255]) ^ I[G++];
                var B = ((H[t >>> 24] << 24) | (H[(y >>> 16) & 255] << 16) | (H[(x >>> 8) & 255] << 8) | H[v & 255]) ^ I[G++];
                A[z] = E;
                A[z + 1] = D;
                A[z + 2] = C;
                A[z + 3] = B
            },
            keySize: 256 / 32
        });
        b.AES = q._createHelper(f)
    } ()); (function() {
        var b = a;
        var c = b.lib;
        var i = c.WordArray;
        var n = c.BlockCipher;
        var j = b.algo;
        var o = [57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35, 27, 19, 11, 3, 60, 52, 44, 36, 63, 55, 47, 39, 31, 23, 15, 7, 62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21, 13, 5, 28, 20, 12, 4];
        var m = [14, 17, 11, 24, 1, 5, 3, 28, 15, 6, 21, 10, 23, 19, 12, 4, 26, 8, 16, 7, 27, 20, 13, 2, 41, 52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48, 44, 49, 39, 56, 34, 53, 46, 42, 50, 36, 29, 32];
        var l = [1, 2, 4, 6, 8, 10, 12, 14, 15, 17, 19, 21, 23, 25, 27, 28];
        var k = [{
            0 : 8421888,
            268435456 : 32768,
            536870912 : 8421378,
            805306368 : 2,
            1073741824 : 512,
            1342177280 : 8421890,
            1610612736 : 8389122,
            1879048192 : 8388608,
            2147483648 : 514,
            2415919104 : 8389120,
            2684354560 : 33280,
            2952790016 : 8421376,
            3221225472 : 32770,
            3489660928 : 8388610,
            3758096384 : 0,
            4026531840 : 33282,
            134217728 : 0,
            402653184 : 8421890,
            671088640 : 33282,
            939524096 : 32768,
            1207959552 : 8421888,
            1476395008 : 512,
            1744830464 : 8421378,
            2013265920 : 2,
            2281701376 : 8389120,
            2550136832 : 33280,
            2818572288 : 8421376,
            3087007744 : 8389122,
            3355443200 : 8388610,
            3623878656 : 32770,
            3892314112 : 514,
            4160749568 : 8388608,
            1 : 32768,
            268435457 : 2,
            536870913 : 8421888,
            805306369 : 8388608,
            1073741825 : 8421378,
            1342177281 : 33280,
            1610612737 : 512,
            1879048193 : 8389122,
            2147483649 : 8421890,
            2415919105 : 8421376,
            2684354561 : 8388610,
            2952790017 : 33282,
            3221225473 : 514,
            3489660929 : 8389120,
            3758096385 : 32770,
            4026531841 : 0,
            134217729 : 8421890,
            402653185 : 8421376,
            671088641 : 8388608,
            939524097 : 512,
            1207959553 : 32768,
            1476395009 : 8388610,
            1744830465 : 2,
            2013265921 : 33282,
            2281701377 : 32770,
            2550136833 : 8389122,
            2818572289 : 514,
            3087007745 : 8421888,
            3355443201 : 8389120,
            3623878657 : 0,
            3892314113 : 33280,
            4160749569 : 8421378
        },
        {
            0 : 1074282512,
            16777216 : 16384,
            33554432 : 524288,
            50331648 : 1074266128,
            67108864 : 1073741840,
            83886080 : 1074282496,
            100663296 : 1073758208,
            117440512 : 16,
            134217728 : 540672,
            150994944 : 1073758224,
            167772160 : 1073741824,
            184549376 : 540688,
            201326592 : 524304,
            218103808 : 0,
            234881024 : 16400,
            251658240 : 1074266112,
            8388608 : 1073758208,
            25165824 : 540688,
            41943040 : 16,
            58720256 : 1073758224,
            75497472 : 1074282512,
            92274688 : 1073741824,
            109051904 : 524288,
            125829120 : 1074266128,
            142606336 : 524304,
            159383552 : 0,
            176160768 : 16384,
            192937984 : 1074266112,
            209715200 : 1073741840,
            226492416 : 540672,
            243269632 : 1074282496,
            260046848 : 16400,
            268435456 : 0,
            285212672 : 1074266128,
            301989888 : 1073758224,
            318767104 : 1074282496,
            335544320 : 1074266112,
            352321536 : 16,
            369098752 : 540688,
            385875968 : 16384,
            402653184 : 16400,
            419430400 : 524288,
            436207616 : 524304,
            452984832 : 1073741840,
            469762048 : 540672,
            486539264 : 1073758208,
            503316480 : 1073741824,
            520093696 : 1074282512,
            276824064 : 540688,
            293601280 : 524288,
            310378496 : 1074266112,
            327155712 : 16384,
            343932928 : 1073758208,
            360710144 : 1074282512,
            377487360 : 16,
            394264576 : 1073741824,
            411041792 : 1074282496,
            427819008 : 1073741840,
            444596224 : 1073758224,
            461373440 : 524304,
            478150656 : 0,
            494927872 : 16400,
            511705088 : 1074266128,
            528482304 : 540672
        },
        {
            0 : 260,
            1048576 : 0,
            2097152 : 67109120,
            3145728 : 65796,
            4194304 : 65540,
            5242880 : 67108868,
            6291456 : 67174660,
            7340032 : 67174400,
            8388608 : 67108864,
            9437184 : 67174656,
            10485760 : 65792,
            11534336 : 67174404,
            12582912 : 67109124,
            13631488 : 65536,
            14680064 : 4,
            15728640 : 256,
            524288 : 67174656,
            1572864 : 67174404,
            2621440 : 0,
            3670016 : 67109120,
            4718592 : 67108868,
            5767168 : 65536,
            6815744 : 65540,
            7864320 : 260,
            8912896 : 4,
            9961472 : 256,
            11010048 : 67174400,
            12058624 : 65796,
            13107200 : 65792,
            14155776 : 67109124,
            15204352 : 67174660,
            16252928 : 67108864,
            16777216 : 67174656,
            17825792 : 65540,
            18874368 : 65536,
            19922944 : 67109120,
            20971520 : 256,
            22020096 : 67174660,
            23068672 : 67108868,
            24117248 : 0,
            25165824 : 67109124,
            26214400 : 67108864,
            27262976 : 4,
            28311552 : 65792,
            29360128 : 67174400,
            30408704 : 260,
            31457280 : 65796,
            32505856 : 67174404,
            17301504 : 67108864,
            18350080 : 260,
            19398656 : 67174656,
            20447232 : 0,
            21495808 : 65540,
            22544384 : 67109120,
            23592960 : 256,
            24641536 : 67174404,
            25690112 : 65536,
            26738688 : 67174660,
            27787264 : 65796,
            28835840 : 67108868,
            29884416 : 67109124,
            30932992 : 67174400,
            31981568 : 4,
            33030144 : 65792
        },
        {
            0 : 2151682048,
            65536 : 2147487808,
            131072 : 4198464,
            196608 : 2151677952,
            262144 : 0,
            327680 : 4198400,
            393216 : 2147483712,
            458752 : 4194368,
            524288 : 2147483648,
            589824 : 4194304,
            655360 : 64,
            720896 : 2147487744,
            786432 : 2151678016,
            851968 : 4160,
            917504 : 4096,
            983040 : 2151682112,
            32768 : 2147487808,
            98304 : 64,
            163840 : 2151678016,
            229376 : 2147487744,
            294912 : 4198400,
            360448 : 2151682112,
            425984 : 0,
            491520 : 2151677952,
            557056 : 4096,
            622592 : 2151682048,
            688128 : 4194304,
            753664 : 4160,
            819200 : 2147483648,
            884736 : 4194368,
            950272 : 4198464,
            1015808 : 2147483712,
            1048576 : 4194368,
            1114112 : 4198400,
            1179648 : 2147483712,
            1245184 : 0,
            1310720 : 4160,
            1376256 : 2151678016,
            1441792 : 2151682048,
            1507328 : 2147487808,
            1572864 : 2151682112,
            1638400 : 2147483648,
            1703936 : 2151677952,
            1769472 : 4198464,
            1835008 : 2147487744,
            1900544 : 4194304,
            1966080 : 64,
            2031616 : 4096,
            1081344 : 2151677952,
            1146880 : 2151682112,
            1212416 : 0,
            1277952 : 4198400,
            1343488 : 4194368,
            1409024 : 2147483648,
            1474560 : 2147487808,
            1540096 : 64,
            1605632 : 2147483712,
            1671168 : 4096,
            1736704 : 2147487744,
            1802240 : 2151678016,
            1867776 : 4160,
            1933312 : 2151682048,
            1998848 : 4194304,
            2064384 : 4198464
        },
        {
            0 : 128,
            4096 : 17039360,
            8192 : 262144,
            12288 : 536870912,
            16384 : 537133184,
            20480 : 16777344,
            24576 : 553648256,
            28672 : 262272,
            32768 : 16777216,
            36864 : 537133056,
            40960 : 536871040,
            45056 : 553910400,
            49152 : 553910272,
            53248 : 0,
            57344 : 17039488,
            61440 : 553648128,
            2048 : 17039488,
            6144 : 553648256,
            10240 : 128,
            14336 : 17039360,
            18432 : 262144,
            22528 : 537133184,
            26624 : 553910272,
            30720 : 536870912,
            34816 : 537133056,
            38912 : 0,
            43008 : 553910400,
            47104 : 16777344,
            51200 : 536871040,
            55296 : 553648128,
            59392 : 16777216,
            63488 : 262272,
            65536 : 262144,
            69632 : 128,
            73728 : 536870912,
            77824 : 553648256,
            81920 : 16777344,
            86016 : 553910272,
            90112 : 537133184,
            94208 : 16777216,
            98304 : 553910400,
            102400 : 553648128,
            106496 : 17039360,
            110592 : 537133056,
            114688 : 262272,
            118784 : 536871040,
            122880 : 0,
            126976 : 17039488,
            67584 : 553648256,
            71680 : 16777216,
            75776 : 17039360,
            79872 : 537133184,
            83968 : 536870912,
            88064 : 17039488,
            92160 : 128,
            96256 : 553910272,
            100352 : 262272,
            104448 : 553910400,
            108544 : 0,
            112640 : 553648128,
            116736 : 16777344,
            120832 : 262144,
            124928 : 537133056,
            129024 : 536871040
        },
        {
            0 : 268435464,
            256 : 8192,
            512 : 270532608,
            768 : 270540808,
            1024 : 268443648,
            1280 : 2097152,
            1536 : 2097160,
            1792 : 268435456,
            2048 : 0,
            2304 : 268443656,
            2560 : 2105344,
            2816 : 8,
            3072 : 270532616,
            3328 : 2105352,
            3584 : 8200,
            3840 : 270540800,
            128 : 270532608,
            384 : 270540808,
            640 : 8,
            896 : 2097152,
            1152 : 2105352,
            1408 : 268435464,
            1664 : 268443648,
            1920 : 8200,
            2176 : 2097160,
            2432 : 8192,
            2688 : 268443656,
            2944 : 270532616,
            3200 : 0,
            3456 : 270540800,
            3712 : 2105344,
            3968 : 268435456,
            4096 : 268443648,
            4352 : 270532616,
            4608 : 270540808,
            4864 : 8200,
            5120 : 2097152,
            5376 : 268435456,
            5632 : 268435464,
            5888 : 2105344,
            6144 : 2105352,
            6400 : 0,
            6656 : 8,
            6912 : 270532608,
            7168 : 8192,
            7424 : 268443656,
            7680 : 270540800,
            7936 : 2097160,
            4224 : 8,
            4480 : 2105344,
            4736 : 2097152,
            4992 : 268435464,
            5248 : 268443648,
            5504 : 8200,
            5760 : 270540808,
            6016 : 270532608,
            6272 : 270540800,
            6528 : 270532616,
            6784 : 8192,
            7040 : 2105352,
            7296 : 2097160,
            7552 : 0,
            7808 : 268435456,
            8064 : 268443656
        },
        {
            0 : 1048576,
            16 : 33555457,
            32 : 1024,
            48 : 1049601,
            64 : 34604033,
            80 : 0,
            96 : 1,
            112 : 34603009,
            128 : 33555456,
            144 : 1048577,
            160 : 33554433,
            176 : 34604032,
            192 : 34603008,
            208 : 1025,
            224 : 1049600,
            240 : 33554432,
            8 : 34603009,
            24 : 0,
            40 : 33555457,
            56 : 34604032,
            72 : 1048576,
            88 : 33554433,
            104 : 33554432,
            120 : 1025,
            136 : 1049601,
            152 : 33555456,
            168 : 34603008,
            184 : 1048577,
            200 : 1024,
            216 : 34604033,
            232 : 1,
            248 : 1049600,
            256 : 33554432,
            272 : 1048576,
            288 : 33555457,
            304 : 34603009,
            320 : 1048577,
            336 : 33555456,
            352 : 34604032,
            368 : 1049601,
            384 : 1025,
            400 : 34604033,
            416 : 1049600,
            432 : 1,
            448 : 0,
            464 : 34603008,
            480 : 33554433,
            496 : 1024,
            264 : 1049600,
            280 : 33555457,
            296 : 34603009,
            312 : 1,
            328 : 33554432,
            344 : 1048576,
            360 : 1025,
            376 : 34604032,
            392 : 33554433,
            408 : 34603008,
            424 : 0,
            440 : 34604033,
            456 : 1049601,
            472 : 1024,
            488 : 33555456,
            504 : 1048577
        },
        {
            0 : 134219808,
            1 : 131072,
            2 : 134217728,
            3 : 32,
            4 : 131104,
            5 : 134350880,
            6 : 134350848,
            7 : 2048,
            8 : 134348800,
            9 : 134219776,
            10 : 133120,
            11 : 134348832,
            12 : 2080,
            13 : 0,
            14 : 134217760,
            15 : 133152,
            2147483648 : 2048,
            2147483649 : 134350880,
            2147483650 : 134219808,
            2147483651 : 134217728,
            2147483652 : 134348800,
            2147483653 : 133120,
            2147483654 : 133152,
            2147483655 : 32,
            2147483656 : 134217760,
            2147483657 : 2080,
            2147483658 : 131104,
            2147483659 : 134350848,
            2147483660 : 0,
            2147483661 : 134348832,
            2147483662 : 134219776,
            2147483663 : 131072,
            16 : 133152,
            17 : 134350848,
            18 : 32,
            19 : 2048,
            20 : 134219776,
            21 : 134217760,
            22 : 134348832,
            23 : 131072,
            24 : 0,
            25 : 131104,
            26 : 134348800,
            27 : 134219808,
            28 : 134350880,
            29 : 133120,
            30 : 2080,
            31 : 134217728,
            2147483664 : 131072,
            2147483665 : 2048,
            2147483666 : 134348832,
            2147483667 : 133152,
            2147483668 : 32,
            2147483669 : 134348800,
            2147483670 : 134217728,
            2147483671 : 134219808,
            2147483672 : 134350880,
            2147483673 : 134217760,
            2147483674 : 134219776,
            2147483675 : 0,
            2147483676 : 133120,
            2147483677 : 2080,
            2147483678 : 131104,
            2147483679 : 134350848
        }];
        var g = [4160749569, 528482304, 33030144, 2064384, 129024, 8064, 504, 2147483679];
        var d = j.DES = n.extend({
            _doReset: function() {
                var x = this._key;
                var r = x.words;
                var w = [];
                for (var v = 0; v < 56; v++) {
                    var t = o[v] - 1;
                    w[v] = (r[t >>> 5] >>> (31 - t % 32)) & 1
                }
                var p = this._subKeys = [];
                for (var s = 0; s < 16; s++) {
                    var u = p[s] = [];
                    var y = l[s];
                    for (var v = 0; v < 24; v++) {
                        u[(v / 6) | 0] |= w[((m[v] - 1) + y) % 28] << (31 - v % 6);
                        u[4 + ((v / 6) | 0)] |= w[28 + (((m[v + 24] - 1) + y) % 28)] << (31 - v % 6)
                    }
                    u[0] = (u[0] << 1) | (u[0] >>> 31);
                    for (var v = 1; v < 7; v++) {
                        u[v] = u[v] >>> ((v - 1) * 4 + 3)
                    }
                    u[7] = (u[7] << 5) | (u[7] >>> 27)
                }
                var q = this._invSubKeys = [];
                for (var v = 0; v < 16; v++) {
                    q[v] = p[15 - v]
                }
            },
            encryptBlock: function(q, p) {
                this._doCryptBlock(q, p, this._subKeys)
            },
            decryptBlock: function(q, p) {
                this._doCryptBlock(q, p, this._invSubKeys)
            },
            _doCryptBlock: function(x, s, q) {
                this._lBlock = x[s];
                this._rBlock = x[s + 1];
                e.call(this, 4, 252645135);
                e.call(this, 16, 65535);
                f.call(this, 2, 858993459);
                f.call(this, 8, 16711935);
                e.call(this, 1, 1431655765);
                for (var z = 0; z < 16; z++) {
                    var v = q[z];
                    var r = this._lBlock;
                    var p = this._rBlock;
                    var w = 0;
                    for (var u = 0; u < 8; u++) {
                        w |= k[u][((p ^ v[u]) & g[u]) >>> 0]
                    }
                    this._lBlock = p;
                    this._rBlock = r ^ w
                }
                var y = this._lBlock;
                this._lBlock = this._rBlock;
                this._rBlock = y;
                e.call(this, 1, 1431655765);
                f.call(this, 8, 16711935);
                f.call(this, 2, 858993459);
                e.call(this, 16, 65535);
                e.call(this, 4, 252645135);
                x[s] = this._lBlock;
                x[s + 1] = this._rBlock
            },
            keySize: 64 / 32,
            ivSize: 64 / 32,
            blockSize: 64 / 32
        });
        function e(r, p) {
            var q = ((this._lBlock >>> r) ^ this._rBlock) & p;
            this._rBlock ^= q;
            this._lBlock ^= q << r
        }
        function f(r, p) {
            var q = ((this._rBlock >>> r) ^ this._lBlock) & p;
            this._lBlock ^= q;
            this._rBlock ^= q << r
        }
        b.DES = n._createHelper(d);
        var h = j.TripleDES = n.extend({
            _doReset: function() {
                var p = this._key;
                var q = p.words;
                this._des1 = d.createEncryptor(i.create(q.slice(0, 2)));
                this._des2 = d.createEncryptor(i.create(q.slice(2, 4)));
                this._des3 = d.createEncryptor(i.create(q.slice(4, 6)))
            },
            encryptBlock: function(q, p) {
                this._des1.encryptBlock(q, p);
                this._des2.decryptBlock(q, p);
                this._des3.encryptBlock(q, p)
            },
            decryptBlock: function(q, p) {
                this._des3.decryptBlock(q, p);
                this._des2.encryptBlock(q, p);
                this._des1.decryptBlock(q, p)
            },
            keySize: 192 / 32,
            ivSize: 64 / 32,
            blockSize: 64 / 32
        });
        b.TripleDES = n._createHelper(h)
    } ()); (function() {
        var g = a;
        var c = g.lib;
        var h = c.StreamCipher;
        var e = g.algo;
        var d = e.RC4 = h.extend({
            _doReset: function() {
                var q = this._key;
                var k = q.words;
                var l = q.sigBytes;
                var m = this._S = [];
                for (var o = 0; o < 256; o++) {
                    m[o] = o
                }
                for (var o = 0,
                n = 0; o < 256; o++) {
                    var s = o % l;
                    var p = (k[s >>> 2] >>> (24 - (s % 4) * 8)) & 255;
                    n = (n + m[o] + p) % 256;
                    var r = m[o];
                    m[o] = m[n];
                    m[n] = r
                }
                this._i = this._j = 0
            },
            _doProcessBlock: function(j, i) {
                j[i] ^= f.call(this)
            },
            keySize: 256 / 32,
            ivSize: 0
        });
        function f() {
            var o = this._S;
            var m = this._i;
            var k = this._j;
            var p = 0;
            for (var q = 0; q < 4; q++) {
                m = (m + 1) % 256;
                k = (k + o[m]) % 256;
                var l = o[m];
                o[m] = o[k];
                o[k] = l;
                p |= o[(o[m] + o[k]) % 256] << (24 - q * 8)
            }
            this._i = m;
            this._j = k;
            return p
        }
        g.RC4 = h._createHelper(d);
        var b = e.RC4Drop = d.extend({
            cfg: d.cfg.extend({
                drop: 192
            }),
            _doReset: function() {
                d._doReset.call(this);
                for (var j = this.cfg.drop; j > 0; j--) {
                    f.call(this)
                }
            }
        });
        g.RC4Drop = h._createHelper(b)
    } ());
    a.mode.CTRGladman = (function() {
        var b = a.lib.BlockCipherMode.extend();
        function e(i) {
            if (((i >> 24) & 255) === 255) {
                var h = (i >> 16) & 255;
                var g = (i >> 8) & 255;
                var f = i & 255;
                if (h === 255) {
                    h = 0;
                    if (g === 255) {
                        g = 0;
                        if (f === 255) {
                            f = 0
                        } else {++f
                        }
                    } else {++g
                    }
                } else {++h
                }
                i = 0;
                i += (h << 16);
                i += (g << 8);
                i += f
            } else {
                i += (1 << 24)
            }
            return i
        }
        function d(f) {
            if ((f[0] = e(f[0])) === 0) {
                f[1] = e(f[1])
            }
            return f
        }
        var c = b.Encryptor = b.extend({
            processBlock: function(n, m) {
                var f = this._cipher;
                var k = f.blockSize;
                var h = this._iv;
                var g = this._counter;
                if (h) {
                    g = this._counter = h.slice(0);
                    this._iv = undefined
                }
                d(g);
                var l = g.slice(0);
                f.encryptBlock(l, 0);
                for (var j = 0; j < k; j++) {
                    n[m + j] ^= l[j]
                }
            }
        });
        b.Decryptor = c;
        return b
    } ()); (function() {
        var b = a;
        var c = b.lib;
        var d = c.StreamCipher;
        var g = b.algo;
        var e = [];
        var f = [];
        var h = [];
        var i = g.Rabbit = d.extend({
            _doReset: function() {
                var u = this._key.words;
                var p = this.cfg.iv;
                for (var r = 0; r < 4; r++) {
                    u[r] = (((u[r] << 8) | (u[r] >>> 24)) & 16711935) | (((u[r] << 24) | (u[r] >>> 8)) & 4278255360)
                }
                var l = this._X = [u[0], (u[3] << 16) | (u[2] >>> 16), u[1], (u[0] << 16) | (u[3] >>> 16), u[2], (u[1] << 16) | (u[0] >>> 16), u[3], (u[2] << 16) | (u[1] >>> 16)];
                var k = this._C = [(u[2] << 16) | (u[2] >>> 16), (u[0] & 4294901760) | (u[1] & 65535), (u[3] << 16) | (u[3] >>> 16), (u[1] & 4294901760) | (u[2] & 65535), (u[0] << 16) | (u[0] >>> 16), (u[2] & 4294901760) | (u[3] & 65535), (u[1] << 16) | (u[1] >>> 16), (u[3] & 4294901760) | (u[0] & 65535)];
                this._b = 0;
                for (var r = 0; r < 4; r++) {
                    j.call(this)
                }
                for (var r = 0; r < 8; r++) {
                    k[r] ^= l[(r + 4) & 7]
                }
                if (p) {
                    var v = p.words;
                    var t = v[0];
                    var s = v[1];
                    var q = (((t << 8) | (t >>> 24)) & 16711935) | (((t << 24) | (t >>> 8)) & 4278255360);
                    var n = (((s << 8) | (s >>> 24)) & 16711935) | (((s << 24) | (s >>> 8)) & 4278255360);
                    var o = (q >>> 16) | (n & 4294901760);
                    var m = (n << 16) | (q & 65535);
                    k[0] ^= q;
                    k[1] ^= o;
                    k[2] ^= n;
                    k[3] ^= m;
                    k[4] ^= q;
                    k[5] ^= o;
                    k[6] ^= n;
                    k[7] ^= m;
                    for (var r = 0; r < 4; r++) {
                        j.call(this)
                    }
                }
            },
            _doProcessBlock: function(n, l) {
                var m = this._X;
                j.call(this);
                e[0] = m[0] ^ (m[5] >>> 16) ^ (m[3] << 16);
                e[1] = m[2] ^ (m[7] >>> 16) ^ (m[5] << 16);
                e[2] = m[4] ^ (m[1] >>> 16) ^ (m[7] << 16);
                e[3] = m[6] ^ (m[3] >>> 16) ^ (m[1] << 16);
                for (var k = 0; k < 4; k++) {
                    e[k] = (((e[k] << 8) | (e[k] >>> 24)) & 16711935) | (((e[k] << 24) | (e[k] >>> 8)) & 4278255360);
                    n[l + k] ^= e[k]
                }
            },
            blockSize: 128 / 32,
            ivSize: 64 / 32
        });
        function j() {
            var r = this._X;
            var q = this._C;
            for (var l = 0; l < 8; l++) {
                f[l] = q[l]
            }
            q[0] = (q[0] + 1295307597 + this._b) | 0;
            q[1] = (q[1] + 3545052371 + ((q[0] >>> 0) < (f[0] >>> 0) ? 1 : 0)) | 0;
            q[2] = (q[2] + 886263092 + ((q[1] >>> 0) < (f[1] >>> 0) ? 1 : 0)) | 0;
            q[3] = (q[3] + 1295307597 + ((q[2] >>> 0) < (f[2] >>> 0) ? 1 : 0)) | 0;
            q[4] = (q[4] + 3545052371 + ((q[3] >>> 0) < (f[3] >>> 0) ? 1 : 0)) | 0;
            q[5] = (q[5] + 886263092 + ((q[4] >>> 0) < (f[4] >>> 0) ? 1 : 0)) | 0;
            q[6] = (q[6] + 1295307597 + ((q[5] >>> 0) < (f[5] >>> 0) ? 1 : 0)) | 0;
            q[7] = (q[7] + 3545052371 + ((q[6] >>> 0) < (f[6] >>> 0) ? 1 : 0)) | 0;
            this._b = (q[7] >>> 0) < (f[7] >>> 0) ? 1 : 0;
            for (var l = 0; l < 8; l++) {
                var n = r[l] + q[l];
                var p = n & 65535;
                var m = n >>> 16;
                var k = ((((p * p) >>> 17) + p * m) >>> 15) + m * m;
                var o = (((n & 4294901760) * n) | 0) + (((n & 65535) * n) | 0);
                h[l] = k ^ o
            }
            r[0] = (h[0] + ((h[7] << 16) | (h[7] >>> 16)) + ((h[6] << 16) | (h[6] >>> 16))) | 0;
            r[1] = (h[1] + ((h[0] << 8) | (h[0] >>> 24)) + h[7]) | 0;
            r[2] = (h[2] + ((h[1] << 16) | (h[1] >>> 16)) + ((h[0] << 16) | (h[0] >>> 16))) | 0;
            r[3] = (h[3] + ((h[2] << 8) | (h[2] >>> 24)) + h[1]) | 0;
            r[4] = (h[4] + ((h[3] << 16) | (h[3] >>> 16)) + ((h[2] << 16) | (h[2] >>> 16))) | 0;
            r[5] = (h[5] + ((h[4] << 8) | (h[4] >>> 24)) + h[3]) | 0;
            r[6] = (h[6] + ((h[5] << 16) | (h[5] >>> 16)) + ((h[4] << 16) | (h[4] >>> 16))) | 0;
            r[7] = (h[7] + ((h[6] << 8) | (h[6] >>> 24)) + h[5]) | 0
        }
        b.Rabbit = d._createHelper(i)
    } ());
    a.mode.CTR = (function() {
        var c = a.lib.BlockCipherMode.extend();
        var b = c.Encryptor = c.extend({
            processBlock: function(l, k) {
                var d = this._cipher;
                var h = d.blockSize;
                var f = this._iv;
                var e = this._counter;
                if (f) {
                    e = this._counter = f.slice(0);
                    this._iv = undefined
                }
                var j = e.slice(0);
                d.encryptBlock(j, 0);
                e[h - 1] = (e[h - 1] + 1) | 0;
                for (var g = 0; g < h; g++) {
                    l[k + g] ^= j[g]
                }
            }
        });
        c.Decryptor = b;
        return c
    } ()); (function() {
        var b = a;
        var c = b.lib;
        var d = c.StreamCipher;
        var g = b.algo;
        var e = [];
        var f = [];
        var h = [];
        var i = g.RabbitLegacy = d.extend({
            _doReset: function() {
                var u = this._key.words;
                var p = this.cfg.iv;
                var l = this._X = [u[0], (u[3] << 16) | (u[2] >>> 16), u[1], (u[0] << 16) | (u[3] >>> 16), u[2], (u[1] << 16) | (u[0] >>> 16), u[3], (u[2] << 16) | (u[1] >>> 16)];
                var k = this._C = [(u[2] << 16) | (u[2] >>> 16), (u[0] & 4294901760) | (u[1] & 65535), (u[3] << 16) | (u[3] >>> 16), (u[1] & 4294901760) | (u[2] & 65535), (u[0] << 16) | (u[0] >>> 16), (u[2] & 4294901760) | (u[3] & 65535), (u[1] << 16) | (u[1] >>> 16), (u[3] & 4294901760) | (u[0] & 65535)];
                this._b = 0;
                for (var r = 0; r < 4; r++) {
                    j.call(this)
                }
                for (var r = 0; r < 8; r++) {
                    k[r] ^= l[(r + 4) & 7]
                }
                if (p) {
                    var v = p.words;
                    var t = v[0];
                    var s = v[1];
                    var q = (((t << 8) | (t >>> 24)) & 16711935) | (((t << 24) | (t >>> 8)) & 4278255360);
                    var n = (((s << 8) | (s >>> 24)) & 16711935) | (((s << 24) | (s >>> 8)) & 4278255360);
                    var o = (q >>> 16) | (n & 4294901760);
                    var m = (n << 16) | (q & 65535);
                    k[0] ^= q;
                    k[1] ^= o;
                    k[2] ^= n;
                    k[3] ^= m;
                    k[4] ^= q;
                    k[5] ^= o;
                    k[6] ^= n;
                    k[7] ^= m;
                    for (var r = 0; r < 4; r++) {
                        j.call(this)
                    }
                }
            },
            _doProcessBlock: function(n, l) {
                var m = this._X;
                j.call(this);
                e[0] = m[0] ^ (m[5] >>> 16) ^ (m[3] << 16);
                e[1] = m[2] ^ (m[7] >>> 16) ^ (m[5] << 16);
                e[2] = m[4] ^ (m[1] >>> 16) ^ (m[7] << 16);
                e[3] = m[6] ^ (m[3] >>> 16) ^ (m[1] << 16);
                for (var k = 0; k < 4; k++) {
                    e[k] = (((e[k] << 8) | (e[k] >>> 24)) & 16711935) | (((e[k] << 24) | (e[k] >>> 8)) & 4278255360);
                    n[l + k] ^= e[k]
                }
            },
            blockSize: 128 / 32,
            ivSize: 64 / 32
        });
        function j() {
            var r = this._X;
            var q = this._C;
            for (var l = 0; l < 8; l++) {
                f[l] = q[l]
            }
            q[0] = (q[0] + 1295307597 + this._b) | 0;
            q[1] = (q[1] + 3545052371 + ((q[0] >>> 0) < (f[0] >>> 0) ? 1 : 0)) | 0;
            q[2] = (q[2] + 886263092 + ((q[1] >>> 0) < (f[1] >>> 0) ? 1 : 0)) | 0;
            q[3] = (q[3] + 1295307597 + ((q[2] >>> 0) < (f[2] >>> 0) ? 1 : 0)) | 0;
            q[4] = (q[4] + 3545052371 + ((q[3] >>> 0) < (f[3] >>> 0) ? 1 : 0)) | 0;
            q[5] = (q[5] + 886263092 + ((q[4] >>> 0) < (f[4] >>> 0) ? 1 : 0)) | 0;
            q[6] = (q[6] + 1295307597 + ((q[5] >>> 0) < (f[5] >>> 0) ? 1 : 0)) | 0;
            q[7] = (q[7] + 3545052371 + ((q[6] >>> 0) < (f[6] >>> 0) ? 1 : 0)) | 0;
            this._b = (q[7] >>> 0) < (f[7] >>> 0) ? 1 : 0;
            for (var l = 0; l < 8; l++) {
                var n = r[l] + q[l];
                var p = n & 65535;
                var m = n >>> 16;
                var k = ((((p * p) >>> 17) + p * m) >>> 15) + m * m;
                var o = (((n & 4294901760) * n) | 0) + (((n & 65535) * n) | 0);
                h[l] = k ^ o
            }
            r[0] = (h[0] + ((h[7] << 16) | (h[7] >>> 16)) + ((h[6] << 16) | (h[6] >>> 16))) | 0;
            r[1] = (h[1] + ((h[0] << 8) | (h[0] >>> 24)) + h[7]) | 0;
            r[2] = (h[2] + ((h[1] << 16) | (h[1] >>> 16)) + ((h[0] << 16) | (h[0] >>> 16))) | 0;
            r[3] = (h[3] + ((h[2] << 8) | (h[2] >>> 24)) + h[1]) | 0;
            r[4] = (h[4] + ((h[3] << 16) | (h[3] >>> 16)) + ((h[2] << 16) | (h[2] >>> 16))) | 0;
            r[5] = (h[5] + ((h[4] << 8) | (h[4] >>> 24)) + h[3]) | 0;
            r[6] = (h[6] + ((h[5] << 16) | (h[5] >>> 16)) + ((h[4] << 16) | (h[4] >>> 16))) | 0;
            r[7] = (h[7] + ((h[6] << 8) | (h[6] >>> 24)) + h[5]) | 0
        }
        b.RabbitLegacy = d._createHelper(i)
    } ());
    a.pad.ZeroPadding = {
        pad: function(d, b) {
            var c = b * 4;
            d.clamp();
            d.sigBytes += c - ((d.sigBytes % c) || c)
        },
        unpad: function(c) {
            var d = c.words;
            var b = c.sigBytes - 1;
            while (! ((d[b >>> 2] >>> (24 - (b % 4) * 8)) & 255)) {
                b--
            }
            c.sigBytes = b + 1
        }
    };
    return a
}));

 


织梦发布文章后推送给百度主动推送和更新数据

0311lc.com说:

1、后台系统参数新建字段

cfg_bdtoken:百度接口

cfg_bdhost:你的域名不加http

不懂的下面有附送百度网盘直接替换包和数据库命令包

或者直接数据库输入命令

INSERT INTO `dede_sysconfig` (`aid`,`varname`,`info`,`value`,`type`,`groupid`) VALUES ('832','cfg_bdtoken','百度token','百度token','string','1'); INSERT INTO `dede_sysconfig` (`aid`,`varname`,`info`,`value`,`type`,`groupid`) VALUES ('833','cfg_bdhost','网站域名','你的域名不加http','string','1');

2、找到织梦发布文章的php

默认在dede文件夹中文章模型,article_add.php(发布文档);article_edit.php(修改文档)

其他自行可以在核心》频道模型》内容模型管理

1)修改发布文档article_add.php

找到

$artUrl = MakeArt($arcID,true,true,$isremote);
if($artUrl=='')
{
    $artUrl = $cfg_phpurl."/view.php?aid=$arcID";
}

在下边加入

else{
$urls[]='http://'.$cfg_bdhost.''.$artUrl;  
$api = 'http://data.zz.baidu.com/urls?site='.$cfg_bdhost.'&token='.$cfg_bdtoken;
$ch = curl_init();
$options =  array(
    CURLOPT_URL => $api,
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POSTFIELDS => implode("\n", $urls),
    CURLOPT_HTTPHEADER => array('Content-Type: text/plain'),
);
curl_setopt_array($ch, $options);
$result = curl_exec($ch);
}

然后继续找到,

<a href='catalog_do.php?cid=$typeid&dopost=listArchives'><u>已发布文章管理</u></a>

在下面加入(注意是加入)

<a href=''><u>百度提交返回".$result."</u></a>  
&nbsp;&nbsp;

2)修改更新文档article_edit.php

$artUrl = MakeArt($id,true,true,$isremote);
if($artUrl=='')
{
    $artUrl = $cfg_phpurl."/view.php?aid=$id";
}

在下面加入(注意是加入)

else{
$urls[]='http://'.$cfg_bdhost.''.$artUrl;  
$api = 'http://data.zz.baidu.com/update?site='.$cfg_bdhost.'&token='.$cfg_bdtoken;
$ch = curl_init();
$options =  array(
    CURLOPT_URL => $api,
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POSTFIELDS => implode("\n", $urls),
    CURLOPT_HTTPHEADER => array('Content-Type: text/plain'),
);
curl_setopt_array($ch, $options);
$result = curl_exec($ch);
}

然后继续找到,

<a href='catalog_do.php?cid=$typeid&dopost=listArchives'><u>管理文章</u></a>

在下面加入(注意是加入)

<a href=''><u>百度提交返回".$result."</u></a>  
&nbsp;&nbsp;

可以了 发送文章和更新文章都可以实现推送了

 


秒杀带源码

0311lc.com说:

 

秒杀设计

1.商品展示层 商品展示 就可以了

当用户
秒杀是否开始 n => 进入秒倒计时页面
=> 倒计时完成进入秒杀页面
=>商品是否售罄 y => 秒杀页面结束
n => 带秒杀按钮的跳转页面
=>商品是否售罄 等待商品售罄=>秒杀登记页面

2.用户登记层 让用户登记相关信息

秒杀登记页面

3.数据接入层 登记的信息 接入 到数据库
秒杀登记页面
判断是否提交过数据 =y 秒杀结束页面
n =>ajax 后台数据页面
=> 数据校验 n =>重新登记
y => 存入 redis y => 插入
no => 用户提交异常
=>是否达到销售商品数量最大值 => 返回登记页面

4.数据处理层
接入层 没问题 就存入数据库
redis 放到 mysql里存储
完成通知 1层
通知 2层
通知 3
==============================
第一层 页面
1.商品展示页面====倒计时 倒计时 js
2.商品秒杀进行中
3.秒杀结束页面

cdn 每秒回源
第二层 页面

手机号 邀请码 验证码

简单 过滤 手机号要过滤
ajax 数据发送
ajax跨域
第三层 数据校验
1.检测数据
ajax 跨域安全 token 数据校验
2.存入队列里
高并发流量数据插入 排队 线程池 liunx已经排队了
去重
队列堆栈
nosql redis memcache
mysql
3.检验订单商品数据

第四层
转存 nosql 数据 到 mysql 持久化

 四层

三层

 二层

 一层

 

https://pan.baidu.com/s/12FgMzqMPgoF0-42mINaCFQ

回复文档  打赏1元 发验证码


swoole

0311lc.com说:

环境配置

  • centos7/ubuntu16
  • php 5.5

tcp 服务器
  • 用到的方法
bool  swoole_server->on(
    string $event,
    mixed $callback);
bool  swoole_server->start();
bool  swoole_server->send(
    int $fd,
    string $data,
    int $reactorThreadld=0
    );
function swoole_server->set
  • 代码实现
$host = '0.0.0.0'; // string
$port = 9501;//int
$serv = new swoole_server(
    $host,
    $port
    //$mode,
    //$sock_type
    )
/**
  $host 127.0.0.1 本地  
        192.168.50.133 监听外网
        0.0.0.0   多个个IP

  ipv4/ipv6    ::0 是 ipv6 官网看吧
  $port  端口  1204一些端口 要 root
  9501
  $mode : SWOOLE_PROCESS  多进程
  $sock_type  : SWOOLE_SOCK_TCP

*/
/**
bool $swoole_server->on

$event :    connect   建立连接  $serv  $fd
            receive 当接收数据   $from_id 是id  $data 是数据
            close 关闭

*/

$serv->on('connect',function($serv,$fd){
        var_dump($serv);
        var_dump($fd);
        echo  "建立连接";

})

$serv->on('receive',functon($serv,$fd,$from_id,$data){
    echo  "接收数据";
    var_dump($data);

})

$serv->on('close',functon($serv,$fd){
    echo  "连接关闭";

})

$serv->start();
/**  linux 操作
cat index.php
php index.php
ps -ajft
关闭防火墙
systemctl stop firewalld.service

下载网络调试助手http://www.downcc.com/soft/95312.html
选中 tcp client  ip是远程ip
1.关闭防火墙 2开启服务  php index.php
3.发送  abc  断开 也是提示

UDP 服务器
  • 用到的方法
new  swoole_server(
        string $host,
        int $post,
        int $mode=SWOOLE_PRPCESS,
        int $SWOOLE_PRPCESS,
        int $sock_type=SWOOLE_SOCK_UDP
)
接收到数据 
functon onPacket(
    swoole_server $server,
    sring $data,
    array $client_info);
发送数据
bool swoole_server->sendto(
    string $ip, 
    int $port,
    sting $data,
    int  $serveer_socket = -1
);
  • 代码实现
$serv = new swoole_server(
    '0.0.0.0',
    9502,
    SWOOLE_PROCESS,
    SWOOLE_SOCK_UDP
    );
    //fd 客户端信息
$serv->on('packet',function($serv,$data,$fd){

    //发送数据到相应客户端,反馈信息
    $serv->sendto($fd['address'],$fd['port'],"server:$data");
    var_dump($fd);

});

serv->start(); //启动服务


ps -ajft
php index.php
ps -ajft


下载网络调试助手http://www.downcc.com/soft/95312.html
选中 udp client  ip是远程ip  9502
1.关闭防火墙 2开启服务  php index.php
3.发送  abc  断开 也是提示

web 服务器
  • 用到的方法
new  swoole_http_server();
swoole_http_server 继承 swoole_server
参数1 string $host 监听ip地址
参数2 int $port  监听端口
on/start 函数
  • 代码实现
$serv = new swoole_http_server("0.0.0.0",9501);

$serv->on('request',function($request,$response){

    var_dump($request);
    $response->header("Content-Type","text/html;charset=utf-8");//设置返回头部信息
    $response->end("hello world".rand(100,99));//发送信息


});
$serv->start();


php index.php
ps -ajft
打开浏览器  192.168.**:9501


websocket
  • 用到的方法
 new swoole_websocket_server();

 swoole_websocket_server 继承 swoole_http_server 继承 swoole_server
 on/start 函数
        open/ 建立连接
        message/ 接收信息
        close  关闭
 push() 发送客户端数据

  • 代码实现
 $ws =  new swoole_websocket_server("0.0.0.0",9501);


//  on    
//  open 建立连接   $ws 服务器 $request 客户端信息
$ws->on('open',function($ws,$request){
    var_dump($request);
    $ws->push($request->fd,"welcome \n");

})   

//message 接收信息

$ws->on('message',function($ws,$request){
    echo  "Msessge:$request->data";
    $ws->push($request->fd,"get it message");
})
$ws->on('close',function($ws,$request){
    echo "close\n";
})

$ws->start();

<html>
  <script>
  var wsServer = "ws://1923..312321:9501";

  var  webSocket = new WebSocket(wsServer);

  webSocket.onopen = function(evt){

    console.log("连接成功");
  }

  webSocket.onclose = function (evt){

    console.log("关闭");
  }
  webSocket.onmessage = function(evt){
    console.log(evt.data);
  }
  webSocket.onerror = function(evt,e){
    console.log('error');
  }

  </script>

</html>

刷新浏览器 看服务器端 也接受到消息


定时器
  • 用到的方法
php 实现定时   sleep 太费劲
window  定时任务  linux cron -echo
swoole 定时器 可以

//循环执行多次触发=========swoole_timer_tick=========

参数1  int  $after_time_ms  指定时间毫秒  过多长时间触发
参数2  mixed  $callback functon 执行的函数
参数3  mixed $user_param 用户参数

清楚定时器
bool  swoole_timer_clear(int $time_id);

单次触发 ========= swoole_timer_after=====
参数1  int  $after_time_ms  指定时间毫秒  过多长时间触发
参数2  mixed  $callback functon 执行的函数
参数3  mixed $user_param 用户参数
  • 代码实现
//循环执行
swoole_timer_tick(2000,function($timer_id){
    echo  "2000 执行  $time_id \n "; 
});

//单次执行
swoole_timer_after(3000,function($timer_id){
    echo  "3000执行  $time_id \n "; 
});




php  index.php


异步TCP服务器
  • 用到的方法
task() 函数   投递异步任务
on ("事件".function(){})  处理函数  执行异步函数
finish() 函数   任务处理完成后结果
  • 代码实现
//创建 tcp 服务
$serv = new swoole_server('0.0.0.0',9501);
//设置异步 进程工作数量
$serv->set(array(
    'task_worker_num' => 4
));
//投递异步任务
$serv->on('receive',function($serv,$fd,$from_id,$data){
    $task_id = $serv->task($data);//异步ID
    echo "异步ID:$task_id \n";

});

//处理异步任务

$serv->on('task',function($serv,$task_id,$from_id,$data){

     echo "执行异步ID $task_id":
     $serv->finish("$data  ->  OK ");
});
//处理结束

$serv->on('finish',function($serv,$task_id,$data){
    echo  "执行完成";
});
$serv->start();

  • 命令
php index.php
ps -ajft 
4个异步任务

通过网络助手 
发送 abc
显示 异步 执行完成


TCP客户端
  • 用到的方法
应用比较少
只能命令行 才行
new  swoole_client()

SWOOLE_SOCK_TCP   使用 tcp协议
SWOOLE_SOCK_ASYNC  异步支持

  • 代码实现
$client =  new swoole_client(SWOOLE_SOCK_TCP);
$client->connect("192.168.50.1",8080,5)  or die ("连接失败");//5秒 响应 
$client->

//异步
$client =  new swoole_client(SWOOLE_SOCK_TCP,SWOOLE_SOCK_ASYNC);

$client->on('connect',function($cli){

        $cli->send("hello \n");
});
//注册接收数据 
$client->on('receive',function($cli,$data){

    echo  "data:$data";
});

$client->on("error",function($cli){

    echo "失败\n";
});

$client->on("close",function($cli){

    echo "关闭\n";
});
//发起连接
$client->connect('192.168.50.1',8080,10); //10秒 


进程创建
  • 用到的方法
默认 php 多进程  进程通信 不是很好

new  swoole_process();

参数1:mixed function 回调函数  子进程创建成功后执行函数
参数2:$redirect stdin stdout  重新像子进程标准输入输出

启动 后可以 写入管道  读取键盘输入 阻塞端

$create_pipe 是否创建管道 启动
$redirect_stdin_stdout 后 此选项忽略用户参数 强制true 
如果子进程没有进程通信 ,可以设置false;
  • 代码实现

//创建进程
//进程对应执行函数
function doProcess(swoole_process $worker){

    echo "PID ".$worker->pid."\n";
    sleep(10); //10秒 能看到效果
}
//创建进程

$process = new swoole_process("doProcess");
$pid= $process->start(); //创建一个进程

//创建多个 可以复制

$process = new swoole_process("doProcess");
$pid= $process->start();
$process = new swoole_process("doProcess");
$pid= $process->start();

//等待结束
swoole_process::wait(); //如果 没有就会有僵尸进程


进程事件
  • 用到的方法
可以给每个进程添加 东西
swoole_event_add();
参数1: int $sock 
    int    文件描述符
    mixed   $read_callback 
            就是 stream_socket_client/fsockopen创建的资源流
    sockets资源   就是sockets扩展中的socket_crete创建的资源
            需要在编译时加入 
             ./configure --enable-sockets资源就是
             sockets扩展中的socket_crete创建的资源
参数2 可以读回调函数
  • 代码实现

//创建一个进程 创建3个进程   进程池设计
$workers = []; // 创建进程池
$worker_num = 3; //进程数

for($i=0;$i<$worker_num;$i++){

    $process = new swoole_process('doProcess'); //创建单独新进程
    $pid = $process->start(); //启动进程 并获取pid
    $workers[$pid] = $process; //存入 进程池
}
// 创建进程函数
function doProcess(swoole_process $process){

    $process->write("pid:".$process->pid") ;//子进程写入信息? 吸入到哪管道里了
    echo "写入信息到:$process->pid  $process->callback" ;

}   
//添加时间 向每个子进程添加执行动作

 foreach($workers as $process){
    //添加
    swoole_event_add(
        $process->pipe, //管道
        function($pipe)  use ($process){
            $data = $process->read();//能否读取数据
            echo  "接收到了$data \n";

    });

 }

  • 命令

php  index.php
写入信息到:47999 接收到pid 47999
写入信息到:47991 接收到pid 47991
写入信息到:47939 接收到pid 47939


进程队列通信
  • 用到的方法
/进程外取数据
string swoole_process->pop( int $maxsize = 8192)
 // 进程压数据
bool swoole_process->push( string data)
array swoole_process::wait( bool $blocking = true)
  • 代码实现

$workers = []; // 进程池
$worker_num = 2;//最大进程数

for($i=0;$i<$worker_num;$i++){

    //创建子进程完成 false 才行
    $process = new swoole_process('doProcess',false,false);
    $process->useQueue();//开辟新内存 全局函数 开启队列
    $pid = $process->start();
    $workers[$pid] = $process;

}

//进程执行函数

function doProcess(swoole_process $process){
    $recv = $process->pop();//8192
    echo "从主进程获取数据:$recv \n";
    sleep(5);
    $process->exit(0);


}
//主进程 向子进程添加数据
foreach($workers as $pid =>$process){

    $process->push("hell 子进程 $pid \n");
}
//等待子进程 结束 回收资源

for($i=0;$i<$worker_num;$i++){

    $ret = swoole_process::wait();// 等待执行完成
    $pid = $ret['pid'];
    unset($workers[$pid]);
    echo "子进程退出 $pid \n";


}

  • 命令

php  index.php


进程信号触发器
  • 用到的方法
//一个进程 放那不动  当有个信号 让他出发启动

//接收信号 signal  等待接受信号 会执行 回调函数
bool swoole_process::signal(int $signo,callable $callback);

//发出信号  发出的进程启动信号
bool 
    function swoole_process::alarm(
        int $interval usec,
        int $type = ITIMER_REAL
    )
  • 代码实现

//触发函数
//定时信号

//触发函数异步执行
swoole_process::signal(SIGALRM,function(){
     echo "1\n"; 

});
//定时信号  100毫秒
swoole_process::alarm(100* 1000)

php index.php  
不断的出行 1  跟上面讲的定时 循环 和js 定时一样的
但是 都是异步执行  比如: 当达到一定条数 停止他

//触发函数异步执行 达到 10次停止 修改为
swoole_process::signal(SIGALRM,function(){
     static $i =0;
     echo "1\n"; 
     $i++;
     if($i>10){
        //清除定时器

        swoole_process::alarm(-1)
     }
});

  • 命令
php  index.php


锁机制
  • 用到的方法
文件锁  数据库 行锁 表锁

swoole 内存锁机制

$lock= new swoole_lock(SWOOLE_MUTEX); SWOOLE_MUTEX 文件锁、读写锁、信号量、互斥锁、自旋锁
lock();  上锁
unlock();  解锁
文件锁、读写锁、信号量、互斥锁、自旋锁  到官网看吧

SWOOLE_MUTEX  互斥锁
  • 代码实现
$lock= new swoole_lock(SWOOLE_MUTEX); //互斥锁
echo  "创建互斥锁 \n";

$lock->lock();//开始锁定   相当锁定主进程

if(pcntl_fork > 0){
    sleep(1);
    $lock->unlock();//解锁
}else{
    //子进程的东西
    echo "子进程  等待锁\n"
    $lock->lock(); //子上锁
    echo " 子进程 获取 锁 ";
    $lock->unlock();//释放锁
    exit("子进程退出");

}
echo  "主进程释放锁";
unset($lock);
sleep(1);
echo  "子进程退出";

---------自己练习文件锁 其他锁--------------

  • 命令
php  index.php


异步文件读取
  • 用到的方法
时间超过30秒  以前 php 这么做

现在可以 读取

提供了纯函数  和 面向对象方式 都可以

swoole_async_readfile(string $filename,mixed $callback);
Swoole\Async::readFile(string $filename,mixed $callback);
  • 代码实现
swoole_async_readfile(__DIR__."/1.txt",function($filename,$content){

    echo  "$filename  $content";

})

nano 1.txt 编辑器

异步文件写入
  • 用到的方法
swoole_async_writefile(
    string $filename,  //文件名 必须写权限
    string $fileContent,  // 内容 最大 4M  写内存里所以快不能多
    callable $callback = null, // 写回调函数
    int $flags = 0   //写的选项 可以使用FILE APPEND表示追加文件末尾
)
  • 代码实现
$content = 'hell world';
swoole_async_writefile('2.txt',$content,function($filename){
  echo  "$filename";
},
0 //标识位 
);

异步事件
  • 用到的方法
bool swoole_event_add (
    int $sock,
    mixed $read_callback
    mixed  $write_callback  = null,
    int $flags = null
)
  • 代码实现
$fp = stream socket_client(
        "tcp://www.qq.coom:80",
        $errno,
        $errstr,
        30
        );
fwrite($fp,"GET / /HTTP/1.1\r\nHost:www.qq.com\r\n\r\n");

swoole_event_add($fp,function($fp){
    //异步完成的东西
    $resp =fread($fp,8192);
    var_dump($resp);

    swoole_event_del($fp);
    fclose($fp);

})

echo "这个先执行完成\n"
效果:先执行完成 在前面  后面返回的 都是 异步完成的 东西 

异步mysql操作
  • 用到的方法
swoole_mysql 
connect 
on 
escape
query 
  • 代码实现
//实例化资源

$db = new swoole_mysql();
$config = [
    'host' => '192.168.50.145', //本地mysql
    'user' => 'root',
    'password' => 'root'
    'database' => 'mysql',
    'charset'=>'utf8'

] ;

$db->connect($config,function($db,$r){

    if($r === false){
         var_dump($db->connect_errno,$db->connect_error);
         die('失败');
    }
    //成功
    $sql = " show tables ";
    $db->query($sql,function(swoole_mysql $db,$r){

          if($r === false){

             var_dump($db->error);
            die("操作失败");
         }else if($r === true){
                var_dump($db->affected_rows,$db->insert_id)
         }
         var_dump($r);
         $db->close();
    })

});

案例聊天室
效果展示==IM 聊天

服务器端 实现
客户端  实现

//服务器端代码

//创建websocket

 $ws = new swoole_websocket_server('0.0.0.0',9502);
 //on  open  message  close
$ws->on('open',function($ws,$request){

     echo  "新用户  $request->fd 加入。\n";
     $GLOBALS['fd'][$request->fd]['id'] = $request->fd; //设置用户id
     $GLOBALS['fd'][$request->fd]['name'] = '匿名用户';

}); 
$ws->on('message',function($ws,$request){
    $msg = $GLOBALS['fd'][$request->fd]['name'].':'.$request->data."\n";

    if($strstr($request->data,"name")){ //用户设置昵称
       $GLOBALS['fd'][$request->fd]['name'] = str_replace("#name#","",$request->data);
    }else{ //进行用户信息发送
         //发送到每个一个客户端啊  遍历客户端
         foreach( $GLOBALS['fd'] as $i ){

            $ws->push($i['id'],$msg);
         }

    }
}); 
$ws->on('close',function($ws,$request){
        echo  "客户端-$request --断开链接\n";
        unset($GLOBALS['fd'][$request]); // 清除 连接 
}); 

$ws->start();

//前端页面
websocket.js


TCP和UDP

0311lc.com说:

传输层的两大协议TCP和UDP,到底用哪一个?这是所有基于网络通讯的应用程序在设计、开发时需要考虑的。

下面,我们先分别来看看TCP和UDP的优缺点,在后面,再来分析一下,什么时候该用TCP、什么时候该用UDP。

TCP的优点:

可靠,稳定
TCP的可靠体现在TCP在传递数据之前,会有三次握手来建立连接,而且在数据传递时,有确认、窗口、重传、拥塞控制机制,在数据传完后,还会断开连接用来节约系统资源。

TCP的缺点:

慢,效率低,占用系统资源高,易被攻击
TCP在传递数据之前,要先建连接,这会消耗时间,而且在数据传递时,确认机制、重传机制、拥塞控制机制等都会消耗大量的时间,而且要在每台设备上维护所有的传输连接,事实上,每个连接都会占用系统的CPU、内存等硬件资源。
而且,因为TCP有确认机制、三次握手机制,这些也导致TCP容易被人利用,实现DOS、DDOS、CC等攻击。

UDP的优点:

快,比TCP稍安全
UDP没有TCP的握手、确认、窗口、重传、拥塞控制等机制,UDP是一个无状态的传输协议,所以它在传递数据时非常快。没有TCP的这些机制,UDP较TCP被攻击者利用的漏洞就要少一些。但UDP也是无法避免攻击的,比如:UDP Flood攻击……

UDP的缺点:

不可靠,不稳定
因为UDP没有TCP那些可靠的机制,在数据传递时,如果网络质量不好,就会很容易丢包。

基于上面的优缺点,那么:

什么时候应该使用TCP:
当对网络通讯质量有要求的时候,比如:整个数据要准确无误的传递给对方,这往往用于一些要求可靠的应用,比如HTTP、HTTPS、FTP等传输文件的协议,POP、SMTP等邮件传输的协议。
在日常生活中,常见使用TCP协议的应用如下:

浏览器,用的HTTP

FlashFXP,用的FTP

Outlook,用的POP、SMTP

Putty,用的Telnet、SSH

QQ文件传输

…………

什么时候应该使用UDP:
当对网络通讯质量要求不高的时候,要求网络通讯速度能尽量的快,这时就可以使用UDP。
比如,日常生活中,常见使用UDP协议的应用如下:

QQ语音

QQ视频

TFTP

……

PHP的Socket通信之UDP篇

1.创建一简单的UDP服务器

//服务器信息
$server = ‘udp://127.0.0.1:9998′;
//消息结束符号
$msg_eof = “\n”;
$socket = stream_socket_server($server, $errno, $errstr, STREAM_SERVER_BIND);
if (!$socket) {
die(“$errstr ($errno)”);
}

do {
//接收客户端发来的信息
$inMsg = stream_socket_recvfrom($socket, 1024, 0, $peer);
//服务端打印出相关信息
echo “Client : $peer\n”;
echo “Receive : {$inMsg}”;
//给客户端发送信息
$outMsg = substr($inMsg, 0, (strrpos($inMsg, $msg_eof))).’ — ‘.date(“D M j H:i:s Y\r\n”);
stream_socket_sendto($socket, $outMsg, 0, $peer);

} while ($inMsg !== false);

2.简单的客户端
function udpGet($sendMsg = ”, $ip = ‘127.0.0.1’, $port = ‘9998’){
$handle = stream_socket_client(“udp://{$ip}:{$port}”, $errno, $errstr);
if( !$handle ){
die(“ERROR: {$errno} – {$errstr}\n”);
}
fwrite($handle, $sendMsg.”\n”);
$result = fread($handle, 1024);
fclose($handle);
return $result;
}

$result = udpGet(‘Hello World’);
echo $result;

————————————————
版权声明:本文为CSDN博主「xm1331305」的原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/xm1331305/article/details/38514017

php中连接tcp服务的三种方式

首先需要现有一个 tcp 服务,我们使用 php中的 socket 系列函数实现

复制代码
<?php

//创建socket套接字
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
//设置阻塞模式
socket_set_block($socket);
//为套接字绑定ip和端口
socket_bind($socket,’127.0.0.1′,3046);
//监听socket
socket_listen($socket,4);

while(true)
{
//接收客户端请求
if(($msgsocket = socket_accept($socket)) !== false)
{
//读取请求内容
$buf = socket_read($msgsocket, 8192);
echo “Received msg: $buf \n”;
$str = “this is a service message”;
//向连接的客户端发送数据
socket_write($msgsocket, $str,strlen($str));
//操作完之后需要关闭该连接否则 feof() 函数无法正确识别打开的句柄是否读取完成
socket_close($msgsocket);
}
}
复制代码
连接 tcp 服务:

使用 socket 系列函数连接

复制代码
<?php
$st=”socket send message”;
$length = strlen($st);
//创建tcp套接字
$socket = socket_create(AF_INET,SOCK_STREAM,SOL_TCP);
//连接tcp
socket_connect($socket, ‘127.0.0.1’,3046);
//向打开的套集字写入数据(发送数据)
$s = socket_write($socket, $st, $length);
//从套接字中获取服务器发送来的数据
$msg = socket_read($socket,8190);

echo $msg;
//关闭连接
socket_close($socket);
复制代码

使用 fsockopen 连接

复制代码
<?php
//使用 fsockopen 打开tcp连接句柄
$fp = fsockopen(“tcp://127.0.0.1”,3046);
$msg = “fsockopen send message”;
//向句柄中写入数据
fwrite($fp,$msg);
$ret = “”;
//循环遍历获取句柄中的数据,其中 feof() 判断文件指针是否指到文件末尾
while (!feof($fp)){
stream_set_timeout($fp, 2);
$ret .= fgets($fp, 128);
}
//关闭句柄
fclose($fp);
echo $ret;
复制代码

使用 stream_socket_client 连接

复制代码
<?php
//使用 stream_socket_client 打开 tcp 连接
$fp = stream_socket_client(“tcp://127.0.0.1:3046”);
$msg = “fsockopen send message”;
//向句柄中写入数据
fwrite($fp,$msg);
$ret = “”;
//循环遍历获取句柄中的数据,其中 feof() 判断文件指针是否指到文件末尾
while (!feof($fp)){
stream_set_timeout($fp, 2);
$ret .= fgets($fp, 128);
}
//关闭句柄
fclose($fp);
echo $ret;
复制代码