PHP開發要點與技巧總結(二)

  1. 1 == 'a'、0 == 'a'、97 == '97a'?這裏邊牽涉到的是默認數據類型轉換。
    // 無輸出
    if ('0') {
        echo "'0' is true\n";
    }
    
    //'a' is true
    if ('a') {
        echo "'a' is true\n";
    }
    
    // 無輸出
    if (1 == 'a') {
        echo "1 == 'a' is true\n";
    }
    
    //0 == 'a' is true
    if (0 == 'a') {
        echo "0 == 'a' is true\n";
    }
    
    //97 == '97a' is true
    if (97 == '97a') {
        echo "97 == '97a' is true\n";
    }
  2. 屢次 ++ 與 -- 
    $n = 5;
    echo $n++ * $n--;//30
  3. count / strlen / mb_strlen :count用於統計數組元素或對象屬性個數,但不能用於字串長度統計(不然老是返回1);strlen用於獲取字符串字節長度,而非字符數;mb_strlen獲取多字節編碼字符串的長度。
  4. mysqlnd:當使用mysqlnd而非libmysqlclient做爲MySQL客戶端庫時,buffered queries是默認模式;故要使用unbuffered queries模式,不管使用mysqli、pdo_mysql、mysql三種中的任何一種API都要手動開啓,特別是作大數據集查詢的時候。
    $pdo = new PDO("mysql:host=localhost;dbname=world", 'my_user', 'my_pass');
    $pdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);
    
    $uresult = $pdo->query("SELECT Name FROM City");
    if ($uresult) {
       while ($row = $uresult->fetch(PDO::FETCH_ASSOC)) {
           echo $row['Name'] . PHP_EOL;
       }
    }
  5. Zend Guard:用於對PHP代碼加密與混淆,服務端須要安裝Zend Guard Loader庫來解密。在Ubuntu 64位系統上還須要安裝 lib32z一、libglu1-mesa兩個庫php

    sudo apt-get install lib32z1 libglu1-mesa:i386
  6. OpenSSL對稱加密: openssl 1.0.1版本後,運行時期自動檢測是否支持 AES-NI (Advanced Encryption Standard New Instructions,基本上2010年以後的Intel CPU都支持,另外AMD和ARM的一些型號也支持)。查看處理器是否支持 AES-NI 執行 cat /proc/cpuinfo | grep aes | wc -lhtml

    1) OpenSSL採用PKCS7 CBC填充,而mcrypt無填充。
    2)OpenSSL AES-256至關於MCRYPT_RIJNDAEL_128(32位key),但mcrypt已被廢棄。
    3)先加密,後認證(Message Authenticity,HMAC),防止被篡改的消息仍然被解密。
    4)AES-12八、AES-19二、AES-256密鑰長度分別是12八、19二、256位,AES-128和AES-256加密處理輪數分別是十、14輪。
    5)AES基於數據塊(16字節,不足則填充)加密,包括ECB(Electronic Code Book,電子密碼本)、CBC(Cipher Block Chaining,加密塊鏈)、CFB(Cipher FeedBack,加密反饋)、OFB(Output FeedBack,輸出反饋)、CTR(Counter,計數)五種加密模式。
    6)在OpenSSL模塊中有三種資源類型:第一種是一個 pkey(公鑰或私鑰)標識符,第二種是一個X509證書標識符,第三種是 CSR (證書籤名請求) 標識符。OPENSSL_ZERO_PADDING、OPENSSL_NO_PADDING選項不能用於CBC、CTR。
    7)AES-256-CBC vs AES-256-CTR:CTR加解密都可並行,CBC解密可並行;CTR能避免Padding Oracle Attacks。
    8)OpenSSL與JAVA AES/ECB/PKCS5Padding問題:https://blog.csdn.net/kikajack/article/details/79273612
    9)Java AES/ECB/PCKS5Padding:
    <?php
    
    class Aes
    {
        public $method = 'AES-128-ECB';
        private $key;
    
        public function __construct($key)
        {
            $this->key = substr(openssl_digest(openssl_digest($key, 'sha1', true), 'sha1', true), 0, 16);
        }
    
        /**
         * 密文解密
         * @return string
         */
        public function decrypt($content)
        {
            return $this->_pkcs5Unpad(openssl_decrypt($content, $this->method, $this->key, OPENSSL_ZERO_PADDING), 16);
        }
    
        /**
         *
         */
        public function encrypt($content)
        {
            $content = $this->_pkcs5Pad($content, 16);
            return openssl_encrypt($content, $this->method, $this->key, OPENSSL_ZERO_PADDING);
    
        }
    
        //PKCS5Padding 補碼方式
        private function _pkcs5Pad($text, $blockSize)
        {
            $pad = $blockSize - (strlen($text) % $blockSize);
            return $text . str_repeat(chr($pad), $pad);
        }
    
        private function _pkcs5Unpad($text)
        {
            $end = substr($text, -1);
            $last = ord($end);
            $len = strlen($text) - $last;
            if (substr($text, $len) == str_repeat($end, $last)) {
                return substr($text, 0, $len);
            }
            return false;
        }
    }
  7. parse_url():解析 URL,返回其組成部分
    $url = 'http://username:password@hostname/path?arg=value#anchor';
    
    print_r(parse_url($url));
    
    echo parse_url($url, PHP_URL_PATH);
    
    //Array
    (
        [scheme] => http
        [host] => hostname
        [user] => username
        [pass] => password
        [path] => /path
        [query] => arg=value
        [fragment] => anchor
    )
    /path
  8. parse_str() 與http_build_query():parse_str()將字符串解析成多個變量,http_build_query()生成 URL-encode 以後的請求字符串。
    // http_build_query
    //0=foo&1=bar&2=baz&3=boom&cow=milk&php=hypertext+processor
    //myvar_0=foo&myvar_1=bar&myvar_2=baz&myvar_3=boom&cow=milk&php=hypertext+processor
    $data = array('foo', 'bar', 'baz', 'boom', 'cow' => 'milk', 'php' =>'hypertext processor');
    echo http_build_query($data) . "\n";
    echo http_build_query($data, 'myvar_');
    
    
    // parse_str
    $str = "first=value&arr[]=foo+bar&arr[]=baz";
    parse_str($str, $output);
    echo $output['first'];  // value
    echo $output['arr'][0]; // foo bar
    echo $output['arr'][1]; // baz
  9. curl
    // 包含響應頭信息
    curl_setopt($ch, CURLOPT_HEADER, 1);
    // 將只獲取響應頭
    curl_setopt($ch, CURLOPT_NOBODY, 1);
    // 重定向是有條件的: ini_get('open_basedir') == '' && ini_get('safe_mode') == false.
    // CURLOPT_FOLLOWLOCATION cannot be activated when in safe_mode or an open_basedir is set...
    // 參考 https://blog.eexit.net/curl-forward-post-over-http-redirections/ curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE);
    // 請求方法
    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
    // 限制最大重定向次數 curl_setopt($ch, CURLOPT_MAXREDIRS, 5); // 返回響應內容而不是直接輸出到頁面 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); // $post爲數組時,最好用http_build_query($post)將其轉爲字符串 curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post));

     

  10. 外部接口編碼轉換:如從當前編碼UTF-8轉換爲GBK
    header("Content-Type: text/html; charset=GBK");
    echo mb_convert_encoding($html, 'GBK', 'UTF-8');
  11. SoapClient::__soapCall 與 SoapClient::__call:__soapCall參數傳遞方式四值得注意
    $client = new SoapClient("some.wsdl");
    $params = array('username'=>'name', 'password'=>'secret');
    
    // 方式一:
    $client->SomeFunction($a, $b, $c);
    
    // 方式二:
    $client->__soapCall("SomeFunction", array($a, $b, $c));
    
    // 方式三:
    $client->login($params);
    
    // 方式四:
    $client->__soapCall('login', array($params));
    
    // 方式五:
    call_user_func_array(array($client, 'login'), [$params]);
  12. 時間比較mysql

    $holder_birthday = date_create('1984-04-28');
    
    // 方式一:
    $diff = date_diff($holder_birthday, date_create());
    
    // 方式二:
    $diff = $holder_birthday->diff(date_create());
    
    if ($diff->invert || $diff->y < 18) {
        $this->errcodeSet('投保人年齡必須大於18週歲!');
        return false;
    }
  13. 動態訪問對象屬性c++

    $key = 'name';
    
    echo $obj->{$key.'Pro'};
  14. 轉義字符:轉義字符不能以單引號引出,必須以雙引號引出。git

    $this->conf = str_replace("\r\n","\n", $this->conf);
  15. 後期靜態綁定程序員

    class A
    {
        function __construct()
        {
            echo self::class . "\n";
            echo static::class . "\n";
        }
    }
    
    class B extends A
    {
    
    }
    
    // A
    // B
    $s = new B();
  16. 鏈式包含(include/include_once/require/require_once):鏈尾到鏈首的全局做用域是等效的。github

    1. 當一個文件被包含時,其中所包含的代碼繼承了 include 所在行的變量範圍。從該處開始,調用文件在該行處可用的任何變量在被調用的文件中也均可用。不過全部在包含文件中定義的函數和類都具備全局做用域。
    
    2. 若是 include 出現於調用文件中的一個函數裏,則被調用的文件中所包含的全部代碼將表現得如同它們是在該函數內部定義的同樣。因此它將遵循該函數的變量範圍。此規則的一個例外是魔術常量,它們是在發生包含以前就已被解析器處理的。
  17. fwrite/fputs: 當 $fwrite=0 時,下列代碼可能致使死循環。參考http://php.net/manual/vote-note.php?id=96951&page=function.fwrite&vote=upsql

    // BROKEN function - infinite loop when fwrite() returns 0s 
    function fwrite_stream($fp, $string) { 
        for ($written = 0; $written < strlen($string); $written += $fwrite) { 
            $fwrite = fwrite($fp, substr($string, $written)); 
            if ($fwrite === false) { 
                return $written; 
            } 
        } 
        return $written; 
    } 
  18. Windows PHP版本選擇TS & NTS 
  19. string字串操做:一個由字節組成的數組再加上一個整數指明緩衝區長度。並沒有如何將字節轉換成字符的信息,由程序員來決定。字符串由什麼值來組成並沒有限制;特別的,其值爲 0(「NUL bytes」)的字節能夠處於字符串任何位置(不過有幾個函數,在本手冊中被稱爲非「二進制安全」的,也許會把 NUL 字節以後的數據全都忽略)。
    $a = 'fsafsfsfsfsff';
    // sa
    var_dump($a[1] . ${2});
  20. PHP 函數/語法結構與命名空間
    (1)在一個命名空間中,當 PHP 遇到一個非限定的類、函數或常量名稱時,它使用不一樣的優先策略來解析該名稱。類名稱老是解析到當前命名空間中的名稱。所以在訪問系統內部或不包含在命名空間中的類名稱時,必須使用徹底限定名稱。
    
    (2)對於函數和常量來講,若是當前命名空間中不存在該函數或常量,PHP 會退而使用全局空間中的函數或常量。
    
    (3)在用戶自定義命名空間中,PHP內核函數能夠被從新定義,但語言結構卻不行。
  21. namespace 和 use:use常量和函數。命名空間經過關鍵字namespace 來聲明。若是一個文件中包含命名空間,它必須在其它全部代碼以前聲明命名空間,除了一個之外:declare關鍵字。
    <?php
    namespace test;
    define('MESSAGE', 'Hello world!');
    ?>
    namespace Name\Space {  
        const FOO = 42;  
        function f() { echo __FUNCTION__."\n"; }  
    }  
    namespace Xx {  
        use const Name\Space\FOO;  
        use function Name\Space\f;  
    
        echo FOO."\n";  
        f();  
    } 
  22. 大型整數:Large integers must be specified as strings - otherwise, PHP will coerce them to floats, resulting in a loss of precision.
  23. 高精度計算:BC Math & GMP
    // JS: 0.0006 * 100000 = 59.99999999999999
    
    // php: 100000000 * 0.0006 = 59999.99999999999
    
    // php:bcmul(100000000, 0.0006, 0) = 60;

     

  24. HEIF / ImageMagick安裝
    #安裝依賴包(庫),不一樣平臺包(庫)名可能不一樣。若是以安裝可免,經過yum list installed查看。 
    yum -y install gcc-c++ libtool pkg-config libjpeg-devel libpng-devel

    #安裝libde265(HEVC Decoder / h.265),沒有安裝libx265(libheif的HEVC Encoder)
    wget https://github.com/strukturag/libde265/archive/frame-parallel.tar.gz
    tar zxvf frame-parallel.tar.gz
    cd libde265-frame-parallel
    ./autogen.sh
    ./configure
    make
    make install
    #sudo ldconfig /usr/local/lib
    #make uninstall & make distclean

    #安裝libheif
    wget https://github.com/strukturag/libheif/archive/master.tar.gz
    tar zxvf master.tar.gz
    cd libheif-master
    ./autogen.sh
    #下邊這條命令也能夠換成 ./configure libde265_CFLAGS='-I/usr/local/include' libde265_LIBS='-lde265'
    #libde265.pc 所在的目錄

    ./configure PKG_CONFIG_PATH=/usr/local/lib/pkgconfig

    make
    make install
    #可能須要加載動態庫配置/etc/ld.so.conf
    #sudo ldconfig /usr/local/lib
    #heif-convert能把heic轉換成png、jpg
    #/usr/local/bin/heif-convert 1.heic 1.jpeg 將報 「Unknown file type in 1.jpeg」錯誤
    #/usr/local/bin/heif-convert 1.heic 1.jpg
    #安裝imagemagick
    wget http://imagemagick.org/download/ImageMagick.tar.gz
    tar xvzf ImageMagick.tar.gz
    cd ImageMagick-7.0.8
    #環境變量(env可查看全部,export/export -n可設置/刪除指定環境變量)PKG_CONFIG_PATH的值爲libheif.pc所在的目錄。若是configure執行發生錯誤,請查看config.log
    ./configure --disable-openmp PKG_CONFIG_PATH=/usr/local/lib/pkgconfig
    make
    make install
    #sudo ldconfig /usr/local/lib
    #which identify
    #/usr/local/bin/identify /var/www/public/1.heic

    #安裝PHP imagick擴展 pecl
    install imagick #php.ini啓用擴展 extension=imagick.so

    #PHP-FPM reload #systemctl restart php-fpm
    #卸載 #pecl uninstall imagick
    $img = new Imagick();
    $img->readImage(__DIR__ .'/1.heic');
    //$img->resizeImage(320,240,Imagick::FILTER_LANCZOS,1);
    $img->writeImage(__DIR__ . '/1.jpg');
    $img->clear();
  25. isset():檢測變量是否已設置而且非 NULL。若使用 isset() 測試一個被設置成 NULL 的變量,將返回 FALSE。同時要注意的是 null 字符("\0")並不等同於 PHP 的 NULL 常量。 若是一次傳入多個參數,那麼 isset() 只有在所有參數都以被設置時返回 TRUE 計算過程從左至右,中途遇到沒有設置的變量時就會當即中止。數組

     

  26. self類:
    <?php
    class A
    {
        public $a = NULL;
    
        public function __construct($s)
        {
            $this->a = $s;
        }
    
        public function make($s)
        {
            return new self($s);
        }
    
        public function dump($obj)
        {
            if ($obj instanceof self) {
                var_dump($this, $obj);
            }
        }
    }
    
    $obj = new A('Obj-1');
    $obj->dump($obj->make('Obj-2'));
    /public/index.php:19:
    object(A)[1]
      public 'a' => string 'Obj-1' (length=5)
    /public/index.php:19:
    object(A)[2]
      public 'a' => string 'Obj-2' (length=5)
  27. private屬性不可見問題:
    abstract class RuleAbstraction
    {
        // 匹配模式
        private $pattern = null;
        // 校驗對象
        private $subject = null;
    
        public function setSubject($subject) {
            $this->subject = $subject;
        }
    }
    class Email extends RuleAbstraction
    {
        // E-mail正則匹配模式
        private $pattern = '/^(?!_|-)(?>[\w\.-]+)@(?!-)(?>((?>[a-zA-Z0-9-]+)\.)+)[a-zA-Z]{2,46}$/';
    
        /**
         * 校驗EMail地址
         *
         * @return false|int
         */
        public function check()
        {
    var_dump($this);
    return preg_match($this->pattern, $this->subject); } }
    $obj = new Email();
    $obj->setSubject('shuznhi.chen@anlaa.com');
    $obj->check();//0

    var_dump:安全

    object(RuleEngine\Rules\Email)#9 (3) {
      ["pattern":"RuleEngine\Rules\Email":private]=>
      string(69) "/^(?!_|-)(?>[\w\.-]+)@(?!-)(?>((?>[a-zA-Z0-9-]+)\.)+)[a-zA-Z]{2,46}$/"
      ["subject":"RuleEngine\Rules\RuleAbstraction":private]=>
      string(22) "w12.a/qe_@124afasf.com"
      ["pattern":"RuleEngine\Rules\RuleAbstraction":private]=>
      NULL
    }
    object(RuleEngine\Rules\Email)#14 (3) {
      ["pattern":"RuleEngine\Rules\Email":private]=>
      string(69) "/^(?!_|-)(?>[\w\.-]+)@(?!-)(?>((?>[a-zA-Z0-9-]+)\.)+)[a-zA-Z]{2,46}$/"
      ["subject":"RuleEngine\Rules\RuleAbstraction":private]=>
      string(22) "shunzhi.chen@anlaa.com"
      ["pattern":"RuleEngine\Rules\RuleAbstraction":private]=>
      NULL
    }
  28. fmod():回被除數(x)除以除數(y)所得的浮點數餘數。
    $x = 5.7;
    $y = 1.3;
    $r = fmod($x, $y);
    // $r equals 0.5, because 4 * 1.3 + 0.5 = 5.7
    $mod = gmp_mod("8", "3");
    echo gmp_strval($mod) . "\n";// 2
相關文章
相關標籤/搜索