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
相关文章
相关标签/搜索