Laravel 框架外的 Artisan::call()

Posted

技术标签:

【中文标题】Laravel 框架外的 Artisan::call()【英文标题】:Artisan::call() outside the Laravel framework 【发布时间】:2016-08-31 21:37:15 【问题描述】:

我想为 Laravel 5.2

创建一个 cron 作业

我的共享主机(在 OVH 上)只允许我指向文件的完整路径,并且我无法使用 Laravel 文档中推荐的 Cron 条目,即:

* * * * * php /path/to/artisan schedule:run >> /dev/null 2>&1

因此,我必须在 Laravel 框架之外的 .php 文件中调用 Artisan 命令。

这是我的public/cron.php 文件到目前为止的样子:

<?php

require __DIR__.'/../bootstrap/autoload.php';

use Illuminate\Support\Facades\Artisan;

Artisan::call('refresh');

refresh 是我在应用内重新生成缩略图的命令。

通过我的浏览器访问cron.php时(在本地XAMPP上测试),出现如下错误:

Fatal error: Uncaught RuntimeException: A facade root has not been set. in 
C:\xampp\htdocs\site\vendor\laravel\framework\src\Illuminate\Support\Facades\Facade.php:210

Stack trace: 
#0 C:\xampp\htdocs\site\public\cron.php(7): Illuminate\Support\Facades\Facade::__callStatic('call', Array) 
#1 main thrown in C:\xampp\htdocs\site\vendor\laravel\framework\src\Illuminate\Support\Facades\Facade.php on line 210

我也尝试过启动应用,但没有任何区别

$app = require_once __DIR__.'/../bootstrap/app.php';
$app->boot();

为了避免使用 Artisan Facade,我尝试直接调用底层内核类:

use Illuminate\Contracts\Console\Kernel;

$kernel = new Kernel;
$kernel->call('refresh');

但这会返回:

Uncaught Error: Cannot instantiate interface Illuminate\Contracts\Console\Kernel

编辑:这是 OVH cron 界面的屏幕截图。 cron 任务由 OVH 自定义,只允许指向文件的完整路径 uri——该文件将执行我的工匠命令。我的问题是,我应该在这个文件中放什么,它应该是 PHP 文件还是 CMD?

【问题讨论】:

所以你不能用'crontab -e'来编辑你的crontab?如果您无法创建 cronjobs,您将如何定期执行 .file? @codedge OP 说他在 OVH 拥有一个共享主机。 OVH 允许客户在他们的 Manager 中创建 cron 作业。 crontab -e 只是用最喜欢的文本编辑器打开/var/spool/cron/crontabs/&lt;username&gt; 的快捷方式。还有许多其他方法可以将一些内容放入该文件中。显然,脚本也可以处理它。 我更新了问题 我在 your other question 上看到您使用的是 OVH Pro。该主机通常带有 SSH 访问权限:请检查您的管理员... 用户与 FTP 相同,密码也应相同。通过 SSH,您可以使用 crontab -e 使用标准语法并遵循 Laravel 文档来运行您选择的 artisan 命令。 @Arcesilas 我对 SSH 还不够熟悉,我仍然是 FTP 新手用户,但我很快就会开始学习。目前,您的另一个答案非常令人满意,谢谢! 【参考方案1】:

您要做的是从脚本中运行特定的 Artisan 命令。

您可以通过复制artisan.php 并强制输入您想要的内容来实现此目的:

#!/usr/bin/env php
<?php

require __DIR__.'/bootstrap/autoload.php';

$app = require_once __DIR__.'/bootstrap/app.php';

$kernel = $app->make(Illuminate\Contracts\Console\Kernel::class);

$status = $kernel->handle(
    $input = new Symfony\Component\Console\Input\ArrayInput(['command' => 'refresh']),
    new Symfony\Component\Console\Output\ConsoleOutput
);

$kernel->terminate($input, $status);

exit($status);

如果您将此脚本与 artisan.php 进行比较,您会发现我刚刚强制将输入传递给 $kernel-&gt;handle() 方法。它不再从 CLI 读取输入,而是将这些参数作为一个数组。详情请见Symfony Console Component documentation。

如果您需要将参数传递给脚本,只需相应地设置输入:

$input = new Symfony\Component\Console\Input\ArrayInput([
    'command' => 'refresh',
    'arg_foo' => 'foo',
    '--option_bar' => 42
]);

$status = $kernel->handle(
    $input,
    new Symfony\Component\Console\Output\ConsoleOutput
);

现在,你可以把这个脚本放在你想要的地方,它不需要通过浏览器通过网络访问(顺便说一句,它不应该)。

如果您将其放在 OVH 托管的根目录中,我的意思是不在 www,您只需非常简单地填写表格:

如果您希望您的脚本可以通过网络访问(出于明显的安全原因不建议这样做,但仍然如此),请将其放在您的 www 目录中,将路径更改为 bootstrap/autoload.phpbootstrap/app.php 并给出你的脚本一个不容易猜到的名字。

在OVH管理器的表单中,不要忘记在脚本路径的开头添加www/

无需指定php script_name,因为当您选择PHP 版本时,管理员会为您处理。只需输入 PHP 将执行的脚本的路径即可。

【讨论】:

谢谢!这正是我一直在寻找的。非常清晰的分步说明,一切正常。 我必须再等 3 个小时才能交付赏金,但你肯定会得到它;) 谢谢!很高兴它有帮助! 在你的第一个sniper中你有这行$kernel-&gt;terminate($input, $status);,你能解释一下$input是从哪里来的吗? 我的错误。现在它很旧了,我没有代码了......我想我只是忘记正确复制 $status 声明中的 $input 声明(是的,另一个声明中的声明,如原始 artisan文件)。我已经修复了 sn-p。【参考方案2】:

尝试简单:

shell_exec('php artisan refresh');

如果不起作用,请尝试为phpartisan 添加适当的路径。

【讨论】:

这在我的本地主机上完美运行,但是当我尝试生产时,它“破坏”了网站,然后我在浏览时出现随机 500 错误。以下是来自主机的日志:FastCGI: comm with server "/home/xxx.com/public/cron-refresh.php" aborted: idle timeout (300 sec)FastCGI: incomplete headers (0 bytes) received from server "/home/xxx.com/public/cron-refresh.php"FastCGI: An error happend on Fastcgi processing, fallback to CGI【参考方案3】:

如果您只想设置一个 cron 作业。请编辑 crontab 并使用“your/app/path/php artisan cron:job”直接执行您的命令。

【讨论】:

以上是关于Laravel 框架外的 Artisan::call()的主要内容,如果未能解决你的问题,请参考以下文章

laravel 常用命令

如何访问公用文件夹外的图像(Laravel)[重复]

Laravel 工匠制作:资源文件夹外的组件

Laravel 从 /public 文件夹外的 ROOT 调用。获取 NotFoundHttpException

出现在框架外的按钮文本

Tkinter Canvas Postscript 未捕获屏幕框架外的 Window 元素