Laravel開發採坑系列問題

2017年12月22日17:40:03 不定時更新php

版本5.4.Xcss

一下是可能會遇到的坑html

1,必須的寫路由轉發才能訪問控制器,固然你能夠自動路由訪問,可是須要些匹配規則,其實仍是轉發了laravel

好多人討論過自動路由的缺點,可是中小項目用不上,並且暴露在外的接口,如今大多數都是有路由轉發,徹底能夠經過分組來兼容多種開發習慣和需求,並非自動路由就狗屁不是web

2,Laravel 作計劃任務的時候坑真的好多,好比不能直接跨控制器訪問,web的是web的路由,console是它本身的,因此你的功能和邏輯代碼必須在Repository或者service裏面,否則你懂的,作好邏輯代碼分離數據庫

官方文檔只有用過的才能看得懂,我很無奈json

完整流程windows

app\Console\Commands下創建你的任務文件 數組

SpiderTask.php
<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
//use Illuminate\Support\Facades\Redis;
use App\Repositories\SpiderRepository;//具體邏輯代碼

class SpiderTask extends Command {

    protected $taskserver;

    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'SpiderTask';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'spider every one hour crawl data';
    protected $spider;

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct() {

        parent::__construct();
        $this->spider = new SpiderRepository();
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle() {
        $this->spider->do_all();//具體執行地方
    }

}

 

而後註冊到Kernel.php服務器

<?php

namespace App\Console;

use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
use App\Repositories\SpiderRepository;//個人具體邏輯代碼地方

class Kernel extends ConsoleKernel {

    /**
     * The Artisan commands provided by your application.
     *
     * @var array
     */
    protected $commands = [
        //
        'App\Console\Commands\SpiderTask', //必須
    ];

    /**
     * Define the application's command schedule.
     *
     * @param  \Illuminate\Console\Scheduling\Schedule  $schedule
     * @return void
     */
    protected function schedule(Schedule $schedule) {
//        $schedule->call(function () {
//            $Spider = new SpiderRepository();
//            $Spider->do_all();
//        })->daily();
        $schedule->command('SpiderTask')->daily();
//兩種方法均可以,建議第二種,邏輯更清晰 }
/** * Register the Closure based commands for the application. * * @return void */ protected function commands() { require base_path('routes/console.php'); } }

注意:

你要測試你的代碼邏輯有沒有錯誤

最好在Linux下測試,由於windows好多問題

在代碼根目錄,若是命令沒有到全局,使用完整路徑

php artisan schedule:run

everyMinute纔會實時運行,能夠看到報錯  

$schedule->command('SpiderTask')->everyMinute();

http://laravelacademy.org/post/6931.html 官方文檔

<?php

namespace App\Repositories;

use App\Models\Spider;
//use phpspider\core\phpspider;
use phpspider\core\requests;
use phpspider\core\selector;

class SpiderRepository {

    use BaseRepository;

    protected $model;

    /**
     * ActivityRepository constructor.
     * @param Activity $activity
     */
    public function __construct() {
        $this->model = new Spider();
    }

    public function do_all() {
        $this->cjysjs();
        $this->shysjs();
        $this->nchn();
        $this->ltbj();
    }

    //長江有色金屬
    public function cjysjs() {
        $html = requests::get('http://www.ccmn.cn/');
        $data = selector::select($html, "#40288092327140f601327141c0560001", "css");
        $data1 = selector::select($data, "tr", "css");
        array_shift($data1);

        $array = array();
        if (!empty($data1) && is_array($data1)) {
            foreach ($data1 as $k => &$v) {
                $data2 = selector::select($v, "td", "css");
                foreach ($data2 as $kk => &$vv) {
                    $vv = str_replace('&#13;', '', $vv);
                    $vv = str_replace(array("\r\n", "\r", "\n"), "", $vv);
                    $vv = trim($vv);
                }
                $data2['3'] = selector::select($data2['3'], "font", "css");
                unset($data2['6']);
                $array[] = $data2;
            }

            if (empty($array)) {
                $info = date("Y-m-d H:i:s", time()) . ':長江有色金屬抓取失敗!';
                Log::info($info);
            }
            $name = 'cjysjs';
            $_data = [];
            if (!empty($array) && is_array($array)) {
                $_data['value'] = json_encode($array);
                $_data['crawl_time'] = time();

                $count = $this->getData($name);
                if (empty($count)) {
                    //增長
                    $_data['name'] = $name;
                    $result = $this->saveData(null, $_data);
                } else {
                    //更新
                    $_data['name'] = $name;
                    $result = $this->saveData($name, $_data);
                }
            }
        }
    }

 public function saveData($name = null, $data = null) {
        return $this->model->updateOrCreate(['name' => $name], $data);
    }

    public function getData($name) {
        return $this->model->where('name', $name)->count();
    }

}

 

添加計劃任務

* * * * * php /path/to/artisan schedule:run >> /dev/null 2>&1
/dev/null 2>&1 必須,其實爲了把錯誤信息和輸出輸出到/dev/null 文件
注意php是不是全局,不是就全路徑,artisan網站根目錄

獲取錯誤
Laravel 調度器爲處理調度任務輸出提供了多個方便的方法。首先,使用sendOutputTo 方法,你能夠發送輸出到文件以便稍後檢查:

$schedule->command('emails:send')
     ->daily()
     ->sendOutputTo($filePath);
若是你想要追加輸出到給定文件,可使用 appendOutputTo 方法:

$schedule->command('emails:send')
     ->daily()
     ->appendOutputTo($filePath);
使用 emailOutputTo 方法,你能夠將輸出發送到電子郵件。使用電子郵件發送任務輸出以前,須要配置 Laravel 的電子郵件服務:

$schedule->command('foo')
     ->daily()
     ->sendOutputTo($filePath)
     ->emailOutputTo('foo@example.com');

 

3,laravel增長第三類或者庫文件

lavavel是封裝的比較好的框架,那麼composer,要麼遵循他的規範,我在使用tcpdf在laravel5.4的時候,發現一個問題

laravel的某種組件要php7以上版本,服務器上又只有5.6我又不想麻煩,想直接引入tcpdf,發現徹底不行,la回去直接經過空間路徑去引入文件讀取,

這樣一來,就不能直接引入,解決方案不難,也不用升級php版本,

composer.json 

"autoload": {
        "classmap": [
            "database",
            "app/Libarary/tcpdf"
        ],
        "psr-4": {
            "App\\": "app/"
        },
        "files": [
            "app/Tools.php",
            "app/WeiXin.php"
        ]
    },

我引入tcpdf在app下面的/Libarary/tcpdf

而後

composer dumpautoload  

注意,若是你本地composer比較麻煩,你能夠在虛擬機上執行,在吧代碼拉回來,由於windows上實在難用

代碼使用比較簡單

use TCPDF;

public function index() {
$pdf = new TCPDF(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false);
}

就OK了

 

4,在某些特殊環境下模型的 create方法,會把很大的數字 2018011900012 轉換成 -622729113的負數,數據庫存的string varchar,底層緣由未知

解決方法,若是數據庫裏是varchar ,本身手動強制轉換一下,若是是 (string)$order_key; 若是是int,你也可能會出現這個問題,也須要轉換一下(int)

 

5,

location / {
            try_files $uri $uri/ /index.php?$query_string;
            index  index.html index.htm index.php;
            #autoindex  on;
        }

 

 正常在NGINX的配置文件都須要加上這一段laravel才能夠正常運行,可是直接從網上的找了一段是這樣的

location / {
            try_files /$uri /$uri/ /index.php?\$query_string;
            index  index.html index.htm index.php;
            #autoindex  on;
        }

坑爹致使 全部get參數都會現成

好比 index.php?type=ee

$this->request->all();

array{

 [\type] => ee

}

還覺得是laravel須要什麼特殊處理,結果是配置文件出錯

 

 

 5,laravel意外bug

#0 [internal function]: Illuminate\Foundation\Bootstrap\HandleExceptions->handleError(2, 'array_shift() e...', '/data/wwwroot/z...', 37, Array)
#1 /data/wwwroot/zs_web/app/Repositories/SpiderRepository.php(37): array_shift(false)
#2 /data/wwwroot/zs_web/app/Repositories/SpiderRepository.php(26): App\Repositories\SpiderRepository->cjysjs()
#3 /data/wwwroot/zs_web/app/Console/Commands/SpiderTask.php(45): App\Repositories\SpiderRepository->do_all()
#4 [internal function]: App\Console\Commands\SpiderTask->handle()
#5 /data/wwwroot/zs_web/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(30): call_user_func_array(Array, Array)
#6 /data/wwwroot/zs_web/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(87): Illuminate\Container\BoundMethod::Illuminate\Container\{closure}()
#7 /data/wwwroot/zs_web/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(31): Illuminate\Container\BoundMethod::callBoundMethod(Object(Illuminate\Foundation\Application), Array, Object(Closure))
#8 /data/wwwroot/zs_web/vendor/laravel/framework/src/Illuminate/Container/Container.php(539): Illuminate\Container\BoundMethod::call(Object(Illuminate\Foundation\Application), Array, Array, NULL)
#9 /data/wwwroot/zs_web/vendor/laravel/framework/src/Illuminate/Console/Command.php(182): Illuminate\Container\Container->call(Array)
#10 /data/wwwroot/zs_web/vendor/symfony/console/Command/Command.php(274): Illuminate\Console\Command->execute(Object(Symfony\Component\Console\Input\ArgvInput), Object(Illuminate\Console\OutputStyle))
#11 /data/wwwroot/zs_web/vendor/laravel/framework/src/Illuminate/Console/Command.php(168): Symfony\Component\Console\Command\Command->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Illuminate\Console\OutputStyle))
#12 /data/wwwroot/zs_web/vendor/symfony/console/Application.php(952): Illuminate\Console\Command->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#13 /data/wwwroot/zs_web/vendor/symfony/console/Application.php(231): Symfony\Component\Console\Application->doRunCommand(Object(App\Console\Commands\SpiderTask), Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#14 /data/wwwroot/zs_web/vendor/symfony/console/Application.php(132): Symfony\Component\Console\Application->doRun(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#15 /data/wwwroot/zs_web/vendor/laravel/framework/src/Illuminate/Foundation/Console/Kernel.php(122): Symfony\Component\Console\Application->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#16 /data/wwwroot/zs_web/artisan(36): Illuminate\Foundation\Console\Kernel->handle(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#17 {main} 
array_shift(false)

致使這樣的一個bug

 

代碼會招致權限問題,個人天,通過分析是write的時候

protected function write(array $record)
    {
        if (!is_resource($this->stream)) {
            if (null === $this->url || '' === $this->url) {
                throw new \LogicException('Missing stream url, the stream can not be opened. This may be caused by a premature call to close().');
            }
            $this->createDir();
            $this->errorMessage = null;
            set_error_handler(array($this, 'customErrorHandler'));
            $this->stream = fopen($this->url, 'a');
            if ($this->filePermission !== null) {
                @chmod($this->url, $this->filePermission);
            }
            restore_error_handler();
            if (!is_resource($this->stream)) {
                $this->stream = null;
                throw new \UnexpectedValueException(sprintf('The stream or file "%s" could not be opened: '.$this->errorMessage, $this->url));
            }
        }

 

@chmod($this->url, $this->filePermission); 偶爾出現權限問題,不是能夠重現bug
這個算是框架問題,唉,只能代碼邏輯避免出現上面出現上面的代碼錯誤,減小或者不寫入錯誤寫入日誌
 核心緣由是跑計劃任務的用戶是當前登錄用戶,而php用戶是www,偶爾會出現問題
 
@chmod($this->url, 0777); 就OK了

不改代碼的方案是 crontab -e -u www
www 用戶是php的用戶,吧
* * * * * php /path/to/artisan schedule:run >> /dev/null 2>&1 寫在裏面就O



6,laravel 5.6 mews/captcha 使用小坑
注意版本
1. 安裝
1). 使用 composer 安裝:

composer require mews/captcha

2). 修改 config/app 文件,添加 ServiceProvider:

在 providers 數組內追加以下內容

'providers' => [
    ...
    Mews\Captcha\CaptchaServiceProvider::class,
],

在 aliases 數組內追加以下內容

'aliases' => [
    ...
    'Captcha' => Mews\Captcha\Facades\Captcha::class,
],

3). 運行 php artisan vendor:publish 生成配置文件 config/captcha.php

若是你這麼操做了,新建一個CaptchaController去建立一個驗證碼,可是5.6不是這樣的 

你直接訪問 http://127.0.0.1/captcha  就會去讀取你生產的配置文件,不須要作任何操做

注意:你若是按照之前的好比5.4

public function mews() {

       return Captcha::create('default');
    }


之前就是這樣操做,訪問一個新的路由,若是你仍是這樣作就沒法按照
config/captcha.php的配置生產你的須要的格式的驗證碼

7,5.6版本一些常見報錯和緣由
Symfony \ Component \ HttpKernel \ Exception \ MethodNotAllowedHttpException
405 Method Not Allowed

通常是由於路由 get post請求方式錯誤

 

419 unknown status通常是發送的請求有 csrf-token校驗 ,可是你沒有發送csrf-token這個參數,注意查看http頭是否帶有csrf-token
相關文章
相關標籤/搜索