分类 编程 下的文章

JetBrainsLicenseServer 授权服务类

代码如下:

<?php

/**
 * JetBrains许可服务器
 */
class JetBrainsLicenseServer
{
    // 授权给谁
    public $licensee = 'jxx';
    // license 有效时间(单位:毫秒),默认约为7天多(607875500),原厂 server 传递的数值。
    public $prolongationPeriod = 607875500;
    // RSA 私钥
    public $privateKey = <<<Eof
-----BEGIN RSA PRIVATE KEY-----
MIIBOwIBAAJBALecq3BwAI4YJZwhJ+snnDFj3lF3DMqNPorV6y5ZKXCiCMqj8OeO
mxk4YZW9aaV9ckl/zlAOI0mpB3pDT+Xlj2sCAwEAAQJAW6/aVD05qbsZHMvZuS2A
a5FpNNj0BDlf38hOtkhDzz/hkYb+EBYLLvldhgsD0OvRNy8yhz7EjaUqLCB0juIN
4QIhAMsJQ3xiJemnJ2pD65iRNCC/Kr7jtxbbBwa6ZFLjp12pAiEA54JCn41fF8GZ
90b9L5dtFQB2/yIcGX4Xo7bCvl8DaPMCIBgOZ+2T33QYtwXTOFXiVm/O1qy5ZFcT
6ng0m3BqwsjJAiEAqna/l7wAyP1E4U7kHqbhKxWsiTAUgLDXtzRbMNHFMQECIQCA
xlpXEPqnC3P8if0G9xHomqJ531rOJuzB8fNtRFmxnA==
-----END RSA PRIVATE KEY-----
Eof;

    public function ping($salt, $isAnswer = false)
    {
        $str = '<PingResponse><message></message><responseCode>OK</responseCode><salt>%s</salt></PingResponse>';
        $out = sprintf($str, $salt);
        return $isAnswer ? $this->writeAnswer($out) : $out;
    }

    public function obtainTicket($salt, $isAnswer = false)
    {
        $ticketId = 1;
        $str      = "<ObtainTicketResponse><message></message><prolongationPeriod>%u</prolongationPeriod><responseCode>OK</responseCode><salt>%s</salt><ticketId>%d</ticketId><ticketProperties>licensee=%s\tlicenseType=0\t</ticketProperties></ObtainTicketResponse>";
        $out      = sprintf($str, $this->prolongationPeriod, $salt, $ticketId, $this->licensee);
        return $isAnswer ? $this->writeAnswer($out) : $out;
    }

    public function prolongTicket($salt, $isAnswer = false)
    {
        $ticketId = 1;
        $str      = '<ProlongTicketResponse><message></message><responseCode>OK</responseCode><salt>%s</salt><ticketId>%d</ticketId></ProlongTicketResponse>';
        $out      = sprintf($str, $salt, $ticketId);
        return $isAnswer ? $this->writeAnswer($out) : $out;
    }

    public function releaseTicket($salt, $isAnswer = false)
    {
        $str = '<ReleaseTicketResponse><message></message><responseCode>OK</responseCode><salt>%s</salt></ReleaseTicketResponse>';
        $out = sprintf($str, $salt);
        return $isAnswer ? $this->writeAnswer($out) : $out;
    }

    public function writeAnswer($str)
    {
        $signature    = $this->sign($str);
        $signatureHex = bin2hex($signature);
        $out          = sprintf("<!-- %s -->\n%s", $signatureHex, $str);
        return $out;
    }

    private function sign($data)
    {
        if (empty ($data)) {
            return null;
        }
        $pkeyid = openssl_get_privatekey($this->privateKey);
        if (empty ($pkeyid)) {
            return null;
        }
        $signature = '';
        $verify    = openssl_sign($data, $signature, $pkeyid, OPENSSL_ALGO_MD5);
        openssl_free_key($pkeyid);
        return $verify ? $signature : null;
    }

}

index.php 文件

代码如下:

- 阅读剩余部分 -

mount:挂载

挂载本地光盘:

mount /dev/cdrom /mnt

NFS 挂载:

mount -t nfs 192.168.1.2:/a /b

CentOS 挂载 U 盘:

mkdir /mnt/u
mount /dev/sda1 /mnt/u

查看挂载的情况:

df -h

查看某台主机提供的 NFS 服务:

showmount -e 192.168.1.2
nc -v -w 2 192.168.1.2 -z 2049

umount:卸载

umount /mnt

umount /dev/cdrom

umount /dev/cdrom /mnt

注意:

当你的当前路径为 /mnt 下,即在挂载文件的里面时,卸载会失败,提示:Dev is besy。解决办法:退出挂载的目录。

- 阅读剩余部分 -

下载代码:

composer require medivh/oauth dev-master

GitHub 项目地址:https://github.com/medivh-jay/oauth

QQ 登录

<?php
require 'vendor/autoload.php';

// 配置信息
$config = [
    'appid' => '申请的appid',
    'secret' => '申请的appKey',
    'redirect_uri' => '跳转地址',
    'response_type' => 'code',
    'display' => 'default', // 分 default 和 mobile
    'scope' => 'get_user_info,add_share,list_album,add_album,upload_pic,add_topic,add_one_blog,add_weibo,check_page_fans,add_t,add_pic_t,del_t,get_repost_list,get_info,get_other_info,get_fanslist,get_idolist,add_idol,del_idol,get_tenpay_addr' // 这里可以固定成这个
];

得到认证对象

Driver命名空间下提供了部分认证驱动类,亦可以自己实现,只要继承了OAuthInterface接口, 都可以使用OAuth来调用

$oAuth = \medivh\OAuth\OAuth::register(new \medivh\OAuth\Driver\QQ, $config);

生成登录地址

$oAuth->getAuthorizeURL();

获取access_token

$oAuth->getAccessToken();

获取用户信息

这个方法可以传入两个参数,openid 和 access_token
当服务器保存了用户的 openid 和 access_token 时,可以在用户登录时直接调用这个方法获取用户信息

- 阅读剩余部分 -

代码如下:

$t1 = microtime(true);
// ... 执行代码 ...
$t2 = microtime(true);
echo '耗时 '.round($t2-$t1, 3).' 秒';

microtime() 如果带有 true 参数,将返回一个浮点类型。

这样 t1 和 t2 得到的就是两个浮点数,相减之后得到之间的差。

由于浮点的位数很长,或者说不确定,所以再用 round() 取出小数点后 3 位。

代码如下:

// 设置HTTP状态码
function http_header($num) {
    $http = array(
        100 => "HTTP/1.1 100 Continue",
        101 => "HTTP/1.1 101 Switching Protocols",
        200 => "HTTP/1.1 200 OK",
        201 => "HTTP/1.1 201 Created",
        202 => "HTTP/1.1 202 Accepted",
        203 => "HTTP/1.1 203 Non-Authoritative Information",
        204 => "HTTP/1.1 204 No Content",
        205 => "HTTP/1.1 205 Reset Content",
        206 => "HTTP/1.1 206 Partial Content",
        300 => "HTTP/1.1 300 Multiple Choices",
        301 => "HTTP/1.1 301 Moved Permanently",
        302 => "HTTP/1.1 302 Found",
        303 => "HTTP/1.1 303 See Other",
        304 => "HTTP/1.1 304 Not Modified",
        305 => "HTTP/1.1 305 Use Proxy",
        307 => "HTTP/1.1 307 Temporary Redirect",
        400 => "HTTP/1.1 400 Bad Request",
        401 => "HTTP/1.1 401 Unauthorized",
        402 => "HTTP/1.1 402 Payment Required",
        403 => "HTTP/1.1 403 Forbidden",
        404 => "HTTP/1.1 404 Not Found",
        405 => "HTTP/1.1 405 Method Not Allowed",
        406 => "HTTP/1.1 406 Not Acceptable",
        407 => "HTTP/1.1 407 Proxy Authentication Required",
        408 => "HTTP/1.1 408 Request Time-out",
        409 => "HTTP/1.1 409 Conflict",
        410 => "HTTP/1.1 410 Gone",
        411 => "HTTP/1.1 411 Length Required",
        412 => "HTTP/1.1 412 Precondition Failed",
        413 => "HTTP/1.1 413 Request Entity Too Large",
        414 => "HTTP/1.1 414 Request-URI Too Large",
        415 => "HTTP/1.1 415 Unsupported Media Type",
        416 => "HTTP/1.1 416 Requested range not satisfiable",
        417 => "HTTP/1.1 417 Expectation Failed",
        500 => "HTTP/1.1 500 Internal Server Error",
        501 => "HTTP/1.1 501 Not Implemented",
        502 => "HTTP/1.1 502 Bad Gateway",
        503 => "HTTP/1.1 503 Service Unavailable",
        504 => "HTTP/1.1 504 Gateway Time-out"
    );
    header($http[$num]);
}

相同表结构

INSERT INTO table1 SELECT * FROM table2;

不同表结构

INSERT INTO table1(filed1, ..., filedn) SELECT table2.filed1, ..., table2.filedn FROM table2;

不同数据库

INSERT into db1.table1(id, number, name) 
  SELECT stu.person_id
     , stu.number
     , person.name
FROM db2.t_stu_info AS stu
    , db2.t_person_info as person
    WHERE stu.person_id = person.id

1695043.jpg

问题描述

一般电子商务网站都会遇到如团购、秒杀、特价之类的活动,而这样的活动有一个共同的特点就是访问量激增、上千甚至上万人抢购一个商品。

然而,作为活动商品,库存肯定是很有限的,如何控制库存不让出现超卖,以防止造成不必要的损失,是众多电子商务网站程序员头疼的问题,这同时也是最基本的问题。

条件

总库存:4个商品
请求人:a、1个商品 b、2个商品 c、3个商品

错误示例

$pdo->beginTransaction();
try{
    $result = $pdo->query('select amount from s_store where postID = 12345');
    if($result->amount > 0){
        // quantity 为请求减掉的库存数量
        $pdo->query('update s_store set amount = amount - quantity where postID = 12345');
    }
    // 没有错误则提交事务
    $pdo->commit();
}catch($e \PDOException){
    // 遇到错误则回滚事务
    $pdo->rollBack();
    echo "Failed: " . $e->getMessage();
}

使用 SELECT ... FOR UPDATE

$pdo->beginTransaction();
try{
    // 使用 SELECT ... FOR UPDATE 将此行数据锁住,在提交事务或者回滚事务时自动解开。
    $result = $pdo->query('select amount from s_store where postID = 12345 for update');
    if($result->amount < 0){
        // 抛出异常
        throw new \PDOException('库存不足');
    }
    // quantity 为请求减掉的库存数量
    $pdo->query('update s_store set amount = amount - quantity where postID = 12345');
    // 没有错误则提交事务
    $pdo->commit();
}catch($e \PDOException){
    // 遇到错误则回滚事务
    $pdo->rollBack();
    echo "Failed: " . $e->getMessage();
}

其他方法

- 阅读剩余部分 -

在工作中,我们经常会遇到这样的问题,需要更新库存,当我们查询到可用的库存准备修改时,这时,其他的用户可能已经对这个库存数据进行修改了,导致,我们查询到的数据会有问题,下面我们就来看解决方法。

如果SELECT 后面若要UPDATE 同一个表单,最好使用SELECT ... UPDATE。

举个例子

假设商品表单 products 内有一个存放商品数量的 quantity,在订单成立之前必须先确定 quantity 商品数量是否足够( quantity > 0 ),然后才把数量更新为 1 。

SELECT quantity FROM products WHERE id = 3; UPDATE products SET quantity = 1 WHERE id = 3;

开启事务

为什么不安全呢?

高并发时会出现问题,如果我们需要在 quantity > 0 的情况下才能扣库存,假设程序在第一行 SELECT 读到的 quantity 是 2,但是当 MySQL 正准备要 UPDATE 的时候,可能已经有人把库存扣成 0 了,但是程序却浑然不知,将错就错的 UPDATE 下去了。因此必须利用事务机制来确保读取及提交的数据都是正确的。

BEGIN WORK; SELECT quantity FROM products WHERE id = 3 FOR UPDATE;

此时 products 数据中 id = 3 的数据被锁住,其它事务必须等待此次事务提交后才能执行。

SELECT * FROM products WHERE id = 3 FOR UPDATE;

- 阅读剩余部分 -

事务处理

事务 (transaction) 是由查询和/或更新语句的序列组成。用 begin、start transaction 开始事务,rollback 回滚事务,commit 提交事务。

在开始事务后,可以有若干个 SQL 查询或更新语句,每个 SQL 递交执行后,还应该有判断是否正确执行的语句,以确定下一步是否回滚,若都被正确执行则最后提交事务。

事务一旦回滚,数据库则保持开始事务前状态。就好象一个被编辑的文件不存盘退出,自然还是保持文件原来的样子。

所以,事务可被视为原子操作,事务中的 SQL,要么全部执行,要不一句都不执行。

如果需要一个事务,则必须用 PDO::beginTransaction() 方法来启动,一旦开始了事务,可用 PDO::commit() 或 PDO::rollBack()来完成,这取决于事务中的代码是否运行成功。

Tips: MySQL只有 InnoDB 驱动支持事务处理,默认 MyIsAM 驱动不支持。

代码示例

连接数据库:

<?php
try {
    // 数据库 PDO 连接
    $pdo = new \PDO('mysql:host=localhost;dbname=mydb', 'root', 'root', array(PDO::ATTR_PERSISTENT => true));
    // 开启异常处理
    $pdo->setAttribute(PDO::ATTR_ERRMODE,  PDO::ERRMODE_EXCEPTION);
} catch (\PDOException $e) {
    echo "数据库连接失败:".$e->getMessage();
    exit;
}

事务处理:
在下面例子中,假设为新员工创建一组条目,分配一个为 23 的 ID。除了登记资料,还需要记录工资。

- 阅读剩余部分 -