2015年12月28日 星期一

遠振主機 escapeshellarg() has been disabled for security reasons

用遠振主機又踩雷啦,遠振將escapeshellarg這個函式disabled 所以只要有用到 SebastianBergmann\Environment\Runtime Symfony\Component\Console\Input\Input Symfony\Component\HttpFoundation\File\MimeType\FileBinaryMimeTypeGuesser Symfony\Component\Process\ProcessUtils Tracy\Debugger 都會提示 escapeshellarg() has been disabled for security reasons 不過還好php5.3之後就支援namespace,可以讓我們輕鬆略過這個問題 (如果使用的套件不支援namespace那就只好認命的去修改程式囉) 只要require下面的檔案就可以解決這些問題了 ```php namespace Yuan\Jhen { if (function_exists('escapeshellarg') === true) { function escapeshellarg($input) { return \escapeshellarg($input); } } else { function escapeshellarg($input) { $input = str_replace('\'', '\\\'', $input); return '\''.$input.'\''; } } } namespace SebastianBergmann\Environment { function escapeshellarg($input) { return \Yuan\Jhen\escapeshellarg($input); } } namespace Symfony\Component\Console\Input { function escapeshellarg($input) { return \Yuan\Jhen\escapeshellarg($input); } } namespace Symfony\Component\HttpFoundation\File\MimeType { function escapeshellarg($input) { return \Yuan\Jhen\escapeshellarg($input); } } namespace Symfony\Component\Process { function escapeshellarg($input) { return \Yuan\Jhen\escapeshellarg($input); } } namespace Tracy { function escapeshellarg($input) { return \Yuan\Jhen\escapeshellarg($input); } } ```

2015年12月22日 星期二

利用Git來升級Laravel

照著影片操作,就會出現conflicts,處理完conflicts之後,再執行 ```bash composer install ``` 這樣大致上就升級完畢了,而且如果升級出問題還可以利用git本身的功能來進行還原...

2015年12月20日 星期日

php 偵測語系

```php function getDefaultLanguage() { if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) { return parseDefaultLanguage($_SERVER['HTTP_ACCEPT_LANGUAGE']); } else { return parseDefaultLanguage(null); } } function parseDefaultLanguage($http_accept, $deflang = 'zh-TW') { if (isset($http_accept) && strlen($http_accept) > 1) { # Split possible languages into array $x = explode(',', $http_accept); foreach ($x as $val) { #check for q-value and create associative array. No q-value means 1 by rule if (preg_match("/(.*);q=([0-1]{0,1}.\d{0,4})/i", $val, $matches)) { $lang[$matches[1]] = (float) $matches[2]; } else { $lang[$val] = 1.0; } } #return default language (highest q-value) $qval = 0.0; foreach ($lang as $key => $value) { if ($value > $qval) { $qval = (float) $value; $deflang = $key; } } } return strtolower($deflang); } echo getDefaultLanguage(); ```

資料庫備份工具

```php class DatabaseClone { public $link; public function __construct($host, $username, $password) { $this->link = mysqli_connect($host, $username, $password); mysqli_query($this->link, 'SET NAMES utf8'); mysqli_query($this->link, 'SET AUTOCOMMIT = 0'); mysqli_query($this->link, 'SET UNIQUE_CHECKS = 0'); mysqli_query($this->link, 'SET FOREIGN_KEY_CHECKS = 0'); } public function fetch($query) { $results = []; $query = mysqli_query($this->link, $query); while ($row = mysqli_fetch_assoc($query)) { $results[] = $row; } return $results; } public function copy($copyTo) { set_time_limit(-1); ini_set('memory_limit', -1); $query = mysqli_query($this->link, $sql = 'show databases'); while ($database = mysqli_fetch_assoc($query)) { $database = $database['Database']; if (in_array($database, ['mysql', 'information_schema', 'performance_schema'], true) === true) { continue; } $createDatabase = mysqli_fetch_assoc(mysqli_query($this->link, 'SHOW CREATE DATABASE `'.$database.'`')); mysqli_query($copyTo->link, $sql = 'DROP DATABASE IF EXISTS `'.$database.'`') or var_dump($sql); mysqli_query($copyTo->link, $sql = $createDatabase['Create Database']) or var_dump($sql); mysqli_select_db($this->link, $database); mysqli_select_db($copyTo->link, $database); $query2 = mysqli_query($this->link, $sql = 'show tables'); while ($table = mysqli_fetch_assoc($query2)) { $table = current($table); $createTable = mysqli_fetch_assoc(mysqli_query($this->link, 'SHOW CREATE TABLE `'.$table.'`')); mysqli_query($copyTo->link, $sql = $createTable['Create Table']) or var_dump($sql); $counts = current(mysqli_fetch_assoc(mysqli_query($this->link, 'SELECT COUNT(*) as counts FROM `'.$table.'`'))); $range = range(0, $counts - 1); $offset = 0; $limit = 200; $chunks = array_chunk($range, $limit); foreach ($chunks as $chunk) { $query3 = mysqli_query($this->link, $sql = 'SELECT * FROM `'.$table.'` LIMIT '.$limit.' OFFSET '.$offset) or var_dump($database, $sql); while ($row = mysqli_fetch_assoc($query3)) { $keys = []; $values = []; foreach ($row as $key => $value) { $keys[] = '`'.$key.'`'; $values[] = "'".addslashes($value)."'"; } mysqli_query($copyTo->link, $sql = 'INSERT INTO `'.$table.'` ('.implode(',', $keys).') VALUES ('.implode(',', $values).')') or var_dump($database, $sql); } $offset += count($chunk); } } } } } $database = new DatabaseClone('localhost:3306', 'root', ''); $database->copy(new DatabaseClone('localhost:3308', 'root', '')); ```

2015年11月7日 星期六

使用instance來進行Tracy Panel

```php // PHP程式碼 include __DIR__.'/vendor/autoload.php'; use Tracy\Debugger; use Tracy\IBarPanel; class CustomPanel implements IBarPanel { /** * Renders HTML code for custom tab. * @return string */ public function getTab() { return 'sql'; } /** * Renders HTML code for custom panel. * @return string */ public function getPanel() { $data = $this->data; ob_start(); require __DIR__.'/custompanel.php'; return ob_get_clean(); } public function push($data) { $this->data[] = $data; } public $data = []; private static $_instance; public static function instance() { if (static::$_instance === null) { static::$_instance = new static; } return static::$_instance; } } // 開發環境 $environment = Debugger::DEVELOPMENT; // 啟用 Debugger::enable($environment); Debugger::getBar() ->addPanel(CustomPanel::instance()); $i = 0; CustomPanel::instance()->push([ 'sql' => 'select * from user where id = '.++$i, ]); CustomPanel::instance()->push([ 'sql' => 'select * from user where id = '.++$i, ]); CustomPanel::instance()->push([ 'sql' => 'select * from user where id = '.++$i, ]); ``` ```php //樣板<h1>SQL</h1>

<div class="tracy-inner">
    <table>
        <?php foreach ($data as $key => $value): ?>
            <tr><td><?php echo $value['sql']; ?></td></tr>
        <?php endforeach ?>
    </table>
</div> ```

2015年10月23日 星期五

Laravel的Session不等於PHP Native Session

在Laravel內我們可能寫了以下的程式碼 ```php get('/session', function () { session_start(); session()->put('foo', 'bar'); $_SESSION['foo'] = 'bar'; header('location: '.url('/session/display')); exit; }); get('/session/display', function () { session_start(); ob_start(); dump(session()->get('foo')); dump($_SESSION['foo']); $content = ob_get_clean(); // output null, 'bar' return $content; }); ``` 會發現輸出結果完全不如我們所預期,為什麼會這樣呢?我們就好好的來做個探討吧... ## 原因出在Laravel的Session根本不是用PHP Native Session 在遇到這個狀況後,於是就去查了一下Laravel Session倒底是怎麼一回事,發現Laravel的程式碼內根本沒有執行session_start()啊 ## Laravel Session倒底是怎麼運作的 追了一下Laravel的原始碼,發現它是利用[Illuminate\Session\Middleware\StartSession](https://github.com/illuminate/session/blob/master/Middleware/StartSession.php)來進行php session模擬的, 在Laravel執行的最後階段在將存在記憶體內的資料進行實體寫入, 所以只要在我們只要在程式內任意一個地方執行了php的exit, die, header('location: xxx'); 那Session就不會被存入檔案內,自然在下一次連線也就取不到值了 ## 有沒有解決方案 有,當然有,只要輸入 ```php get('/session', function () { session_start(); session()->put('foo', 'bar'); $_SESSION['foo'] = 'bar'; session()->save(); // 手動寫入 dump($_SESSION['foo']); $content = ob_get_clean(); // output 'bar', 'bar' return $content; }); ``` ## 後記 為什麼會有這一篇的出現,因為我們可能會用很多其它已經寫好的library,但它們就是有用到session_start();外加header, die, exit等等指令啊,所以記錄一下來提醒自己囉

2015年9月20日 星期日

重寫Laravel Socialite

最近需要用到OAuth的Client套件 所以就使用目前最多人使用的Laravel 不過需要的部份只有Laravel Socialite 看了一下composer.json的相依性 ```json "require": { "php": ">=5.4.0", "illuminate/contracts": "~5.0", "illuminate/http": "~5.0", "illuminate/support": "~5.0", "guzzlehttp/guzzle": "~5.0|~6.0", "league/oauth1-client": "~1.0" }, ``` 只需要這些package並不需要整個Laravel 所以就開始使用它 不過在使用的過程遇到了不少問題 它所需要的package其實不止這些 所以程式在撰寫的過程中確實遇到不少問題 再在上在本機端上開發會遇到cURL error 60: SSL certificate problem 於是決定以[PHPoAuthLib](https://github.com/Lusitanian/PHPoAuthLib.git)進行開發 所以就寫了[Recca0120 Socialite](https://github.com/recca0120/Socialite) 並使它可以獨立使用 [Demo](https://github.com/recca0120/Socialite/tree/master/demo) 目前只先實作Laravel Socialite原本的功能,之後會視情形再加功能 OAuth1 BitBucket Twitter OAuth2 Facebook GitHub Google Instagram LinkedIn