php 中ob_flush函数 和 flush函数

ob_flush()函数: 取出PHP buffering中的数据,放入server buffering

flush()函数: 取出Server buffering的数据,放入browser buffering

例如代码:

         <?php
             echo str_repeat('m0sh1' ,1000);    
             for($i=0;$i<4;$i++) {
                 echo $i.'<br />';
                 ob_flush();
                 flush();
                 sleep(1);
             }
         ?>
          <?php
               //header("content-type:text/html;charset='utf-8'");
               // 提示错误 Cannot modify header information - headers already sent by
          ?>

执行发现

这里代码输出结果是一行一行输出的,
 注意:正确使用二者的顺序是. 先ob_flush, 然后flush

此文章通过 python 爬虫创建,原文是自己的csdn 地址: php 中ob_flush函数 和 flush函数

部分支付宝插件开发bug

感觉有点标题党,但是有些插件确实开发的不规范。

之前开发的支付宝支付模块直接下载的网上提供的支付宝插件,只是做了一些简单的修改。所以没有仔细阅读也就没有发现bug。

我开发的网站使用的是magento 框架。但是不论什么框架插件不规范的道理应该是一样的。

说了这么多其实就是 支付宝异步通知传回的通知状态中

TRADE_FINISHED 和 TRADE_SUCCESS 的区别(已经知道的大牛请不要嘲笑我这个刚过来开发支付模块的菜鸟了 大笑

其实 支付宝即时到帐接口的文档中也有总结状态的说明,但是我自己认为不明确啊(应该是我理解能力太差了吧 - -!)

BUG描述:开发完毕,支付等流程都正常。但是三个月后又会收到支付宝发来的异步通知。如果没有去明确判断TRADE_FINISHED还是

TRADE_SUCCESS 都统一做业务处理那么就会发生bug。

买家付款后,商家能够收到支付宝的 TRADE_SUCCESS 状态的说明你开通的是即时到帐高级接口。普通的是只能收到 TRADE_FINISHED 状态的,即不能进行退款等操作。

其实普通即时到帐接口在某些插件中应该都不会出现bug。因为他们就一个 TRADE_FINISHED 状态。

实际上这里面最重要的区别就是开通 高级即时到帐接口的商家,在买家付钱后会收到一个 TRADE_SUCCESS 的通知,这表示买家成功付钱,同时商家可以进行退款等操做,

之后会在三个月后支付宝再次发来通知 ,即发来TRADE_FINISHED 的通知。以为者交易结束,商家不能再做退款等操作了。

说说我下载的那个支付宝插件 处理异步通知的函数吧。

它在notify 那个函数中判断订单成功使用了 “或” 运算符

if ($postData['trade_status'] == 'TRADE_FINISHED' || $postData['trade_status'] == 'TRADE_SUCCESS'){
   // 业务处理逻辑
   // 例如修改订单状态 发送邮件通知等
}

那么 付款后没什么问题,但是三个月后买家又会收到邮件通知,以及订单状态又改为付完钱的状态。

因为我们有邮件抄送给管理员的操作才发现了这个问题。

其实问题描述起来就是这么简单。明白了怎么回事,解决办法不用说应该也都知道。

但是其实还有许多人不知道或者说没有明确意识到这里面的差别。 出问题后去网上搜索,就连支付宝论坛里面还有

开发者说这两个没什么区别。 重要的是当问道这两个状态的区别是应当具体描述出来三个月继续发送 TRADE_FINISHED 的通知这么一个点。

顺便提一下,支付宝文档里面明确的在商户业务处理注意事项中提出:

但是为什么不点出来 三个月后会发来 TRADE_FINISHED 的通知呢? (当然demo中有明确提出)

我只是觉得文档中有必要明确解释一下。(个人建议而已)

--------------------------------------------------------------------------------------------------------------------------------

这个同样适用于现在版本的 支付宝无线支付接口, 你可以将买家付款 发来的异步通知信息打印,主要是观察 trade_status 如果是 TRADE_FINISHED

说明你没有开通高级即时到帐接口,可以通过支付宝人工客服去修改。但要5个工作日才能改好。

--------------------------------------------------------------------------------------------------------------------------------

提一个问题:

用户下单,跳转到支付宝,登录支付宝账户但是不结账。此时去个人支付宝页面会看到在交易明细中有一个待付款的交易。

这里如果用户或者商家 将订单取消,但是用户从这个地方付款还是可以的。、

这种问题是怎么解决的呢?有没有什么接口通知支付宝这笔交易已取消呢?

此文章通过 python 爬虫创建,原文是自己的csdn 地址: 部分支付宝插件开发bug

php 随机生成数字字母组合

直接上代码:

function getRandomString($len, $chars=null)
{
    if (is_null($chars)) {
        $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    }
    mt_srand(10000000*(double)microtime());
    for ($i = 0, $str = '', $lc = strlen($chars)-1; $i < $len; $i++) {
        $str .= $chars[mt_rand(0, $lc)];
    }
    return $str;
}

例如随机生成 2 位 字母和数字组合

只需调用函数 并传参2即可。

echo getRandomString(2);

如果仅仅是生成小写字母你可以使用类似方法

 echo chr(mt_rand(65, 90);

大写字母

 echo chr(mt_rand(97, 122));

此文章通过 python 爬虫创建,原文是自己的csdn 地址: php 随机生成数字字母组合

php中的魔术方法

PHP魔术方法:

__construct(), __destruct(), __call(), __callStatic(), __get(), __set(), __isset(), __unset(), __sleep(), __wakeup(), __toString(), __invoke(), __set_state(), __clone() 和 __debugInfo() 等方法在 PHP 中被称为"魔术方法"(Magic methods)。在命名自己的类方法时不能使用这些方法名,除非是想使用其魔术功能。

__construct(),类的构造函数
__destruct(),类的析构函数
__call(),在对象中调用一个不可访问方法(私有或者不存在)时调用
__callStatic(),用静态方式中调用一个不可访问方法时调用
__get(),获得一个类的成员变量时调用
__set(),设置一个类的成员变量时调用
__isset(),当对不可访问属性调用isset()或empty()时调用
__unset(),当对不可访问属性调用unset()时被调用。
__sleep(),执行serialize()时,先会调用这个函数
__wakeup(),执行unserialize()时,先会调用这个函数
__toString(),类被当成字符串时的回应方法
__invoke(),调用函数的方式调用一个对象时的回应方法
__set_state(),调用var_export()导出类时,此静态方法会被调用。
__clone(),当对象复制完成时调用

__construct()和__destruct()
构造函数__construct()在对象被创建的时候调用,析构函数__destruct()在对象消亡的时候被调用

<?php  
class ConDes
{
    protected $a = '';

    function __construct(){
        echo '在构造函数中<br>';
    }

    function __destruct(){

        echo '在析构函数中<br>';
    }
}

$val = new ConDes();
unset($val);

?><pre name="code" class="php">


输出:

在构造函数中在析构函数中

__call()和__callStatic()在对象中调用一个不可访问方法时会调用这两个方法,后者为静态方法。

<?php  
class MethodTest  
{
    public function __call ($name, $arguments) {
    var_dump($arguments);
        echo "object method $name and ".implode(',',$arguments)."<br>";
    }

    public static function __callStatic ($name, $arguments) {
        echo "static method $name and ".implode(',',$arguments)."<br>";
    }
}

$obj = new MethodTest;
$obj->runTest('in object context','another arg');
MethodTest::runTest('in static context');  
?>

输出:

array (size=2)
  0 => string 'in object context' (length=17)
  1 => string 'another arg' (length=11)

object method runTest and in object context,another arg
static method runTest and in static context

__get(),__set(),__isset()和__unset()

当获取一个不可访问的类成员变量或设置一个不可访问的类成员变量时调用这两个函数。

<?php
class MethodTest  
{
    private $data = array();
    private $a = '';
    public $bbb = '';

    public function __set($name, $value){
        $this->data[$name] = $value;
		echo '__set';
		var_dump($this->data);
    }

    public function __get($name){
		echo '__get';
		var_dump($this->data);
        if(array_key_exists($name, $this->data))
            return $this->data[$name];
        return NULL;
    }

    public function __isset($name){
		echo '__isset';
        return isset($this->data[$name]);
    }

    public function __unset($name){
		echo '__unset';
        unset($this->data[$name]);
    }
}

$in = new MethodTest();
$in->a = 'aaaa';
$aaa = $in->a;
$res = isset($in->c)? 'set':'not set';
echo '<br>'.$res.'<br>';
unset($in->a);
?>

输出:

__set
array (size=1)
  'a' => string 'aaaa' (length=4)
__get
array (size=1)
  'a' => string 'aaaa' (length=4)
__isset
not set
__unset

__sleep()和__wakeup()

当我们在执行serialize()和unserialize()时,会先调用这两个函数。例如我们在序列化一个对象时,这个对象有一个数据库链接,想要在反序列化中恢复链接状态,则可以通过重构这两个函数来实现链接的恢复。

<?php
class Connection {
    public $link;
    private $server, $username, $password, $db;
    
    public function __construct($server, $username, $password, $db)
    {
        $this->server = $server;
        $this->username = $username;
        $this->password = $password;
        $this->db = $db;
        $this->connect();
    }
    
    private function connect()
    {
        $this->link = mysql_connect($this->server, $this->username, $this->password);
        mysql_select_db($this->db, $this->link);
    }
    
    public function __sleep()
    {
    echo 'sleep<br>';
        return array('server', 'username', 'password', 'db');
    }
    
    public function __wakeup()
    {
    echo 'wakeup<br>';
        $this->connect();
    }
}


$a = new Connection('localhost','mosi','moshi','test');
$sql = 'select id,username from user limit 1';
$res = mysql_query($sql,$a->link);
$res = mysql_fetch_array($res);
var_dump($res);

$sres = serialize($a);
mysql_close($a->link);
//unset($a);

$unsres = unserialize($sres);
var_dump($unsres);
$sql = 'select id,username from user limit 1';
$ress = mysql_query($sql,$unsres->link);
$ress = mysql_fetch_array($ress);
var_dump($ress);


?>

输出:

array (size=4)
  0 => string '1' (length=1)
  'id' => string '1' (length=1)
  1 => string 'm0sh1' (length=5)
  'username' => string 'm0sh1' (length=5)
sleep
wakeup
object(Connection)[2]
  public 'link' => resource(6, mysql link)
  private 'server' => string 'localhost' (length=9)
  private 'username' => string 'moshi' (length=4)
  private 'password' => string 'moshi' (length=5)
  private 'db' => string 'test' (length=4)
array (size=4)
  0 => string '1' (length=1)
  'id' => string '1' (length=1)
  1 => string 'm0sh1' (length=5)
  'username' => string 'm0sh1' (length=5)


__toString()

对象当成字符串时的回应方法。例如使用echo $obj;

<?php  
class TestClass  
{
    public function __toString() {
        return 'this is a object';
    }
}

$class = new TestClass();
echo $class;  
?>

输出:

this is a object

这个方法只能返回字符串,而且不可以在这个方法中抛出异常,否则会出现致命错误。

__invoke()

调用函数的方式调用一个对象时的回应方法。

<?php
class Invoke{
	public function __invoke(){
		echo 'in invoke<br>';
	}
}

class noInvoke{

}

$obj = new Invoke();
$obj();

var_dump(is_callable($obj));

$obj2 = new noInvoke();
//$obj2();
var_dump(is_callable($obj2));

输出:

in invoke
boolean true
boolean false

__set_state()

调用var_export()导出类时,此静态方法会被调用。

<?php  
class A  
{
    public $var1;
    public $var2;
	public static function __set_state ($arr) {
        $obj = new A;
        $obj->var1 = 'var11';
        $obj->var2 = $arr['var2'];
        return $obj;
    }
}

$a = new A;
$a->var1 = 5;
$a->var2 = 'foo';
var_dump($a);  
var_export($a);  

eval('$ress = '.var_export($a,true).';');
var_dump($ress);

?>

输出:

object(A)[1]
  public 'var1' => int 5
  public 'var2' => string 'foo' (length=3)
A::__set_state(array( 'var1' => 5, 'var2' => 'foo', ))
object(A)[2]
  public 'var1' => string 'var11' (length=5)
  public 'var2' => string 'foo' (length=3)

__clone()

当对象复制完成时调用。

<?php  
class Singleton {  
    private static $_instance = NULL;

    // 私有构造方法 
    private function __construct() {}

    public static function getInstance() {
        if (is_null(self::$_instance)) {
            self::$_instance = new Singleton();
        }
        return self::$_instance;
    }

    // 防止克隆实例
    public function __clone(){
        die('Clone is not allowed error: ' . E_USER_ERROR);
    }
}


$a = Singleton::getInstance();
$b = Singleton::getInstance();

if( $a === $b ){
	echo 'equal<br>';
}

$c = clone $b;
?>

输出:

equal
Clone is not allowed error: 256

PHP 魔术常量:简介在这里

此文章通过 python 爬虫创建,原文是自己的csdn 地址: php中的魔术方法

PHP魔术常量

魔术常量(Magic constants)

PHP中的常量大部分都是不变的,但是有8个常量会随着他们所在代码位置的变化而变化,这8个常量被称为魔术常量。

    __LINE__,文件中的当前行号
    __FILE__,文件的完整路径和文件名
    __DIR__,文件所在的目录
    __FUNCTION__,函数名称
    __CLASS__,类的名称
    __TRAIT__,Trait的名字
    __METHOD__,类的方法名
    __NAMESPACE__,当前命名空间的名称

这些魔术常量常常被用于获得当前环境信息或者记录日志。

此文章通过 python 爬虫创建,原文是自己的csdn 地址: PHP魔术常量