How can I get the current user executing a Laravel Command? - php

I am trying to build a custom configuration that gets added to my Laravel configuration at boot up. I created an artisan command that allows the developers to place the server into 'test' mode and 'live' mode. This should then force API's to use test keys rather than live keys which works fine.
public function handle()
{
switch(strtoupper($this->argument('m'))) {
case 'LIVE':
\DB::table('server_mode')->where('id', 1)->update([
'mode' => true,
'verified_by' => 'Server'
]);
$this->info('Server is now in LIVE mode');
break;
case 'TEST':
\DB::table('server_mode')->where('id', 1)->update([
'mode' => false,
'verified_by' => 'Server'
]);
$this->info('Server is now in TEST mode');
break;
default:
$this->error('Please enter either LIVE or TEST');
break;
}
}
The problem is, I want to add which developer changed the status. So far, it is hard coded to 'Server'. Is it possible to get the IP or PC information who'm executed the command to store in the DB?

As said in the comments, Jaquarh doesn't try to authenticate. He just wants to get the username of the perso who ran the command.
You can use $processUser = exec('whoami'); to get the current user name. (It won't work on windows)
However, be careful, usernames are not always very informative. My laptop at work came preinstalled with a user name "User".
Another idea that I can suggest is to force a "name" parameter when using your command.

Related

A way to call a command prompt function from controller in Laravel?

I'm trying to make a thumbnail in a Laravel project and I tried a lot other ways but with no success - Libraries, APIs... The problem is that the project is developed in Windows and the professor needs it in Windows as well.
So far, I experimented to integrate different libraries (wkhtmltoimage, spatie/browsershot, mpdf and s.o.) but in the most of the cases, there are problems with the path.
The required function, which I need, works very good in command prompt and I thought that I must find a way to call it in the controller.
I've tried with:
shell_execute($call);
system($call);
exec($call);
// with $call = "{func_name} {path_to_input_file} {name_of_output_file}";
// Example: $call = "wkhtmltoimage C:\xampp\htdocs\app\public\test.html img.jpg"
But no result. The function generates an image, which I want to store in the database.
Is there an other way to make a call to the command prompt?
Maybe SSH call?
You can execute Artisan commands directly via your controller.
Look at this example from the Laravel documentation:
Route::get('/foo', function () {
$exitCode = Artisan::call('email:send', [
'user' => 1, '--queue' => 'default'
]);
//
});

Recover password mail dosen't send to user laravel

the password recovery email in laravel is not sent to the user
and this is my function in controller :
public function recover(Request $request)
{
$validator = Validator::make($request->only('email'), [
'email' => 'required'
]);
if($validator->fails()) {
throw new ValidationHttpException($validator->errors()->all());
}
$response = Password::sendResetLink($request->only('email'), function (Message $message) {
$message->subject(Config::get('boilerplate.recovery_email_subject'));
});
switch ($response) {
case Password::RESET_LINK_SENT:
// return $this->response->noContent();
return response()->json(['success' => true, 'data' => $response], 200);
case Password::INVALID_USER:
// return $this->response->errorNotFound();
return response()->json(['success' => false, 'data' => $response], 200);
}
}
and I configure my .env and mail.php
I use laravel 5.6
if you are using gmail address to sent mail. then you need to on less secure app.
go to https://myaccount.google.com/lesssecureapps
then allow by turning it on.
and also use
php artisan config:clear
sometimes google blocks when you try to send email through some code. In that case you got a alert mail. click on that mail(Check Activity) and mark as yes (Do you recognize this activity?)
Or you can try
MAIL_DRIVER=sendmail
and also use
php artisan config:clear
First of all, try to locate the problem.
I would suggest to try to setup MAIL_DRIVER=log and check laravel.log after executing this function. If nothing is found in the log - then you're not trying to send it. Most common problem, in this case, is using queues, so, check the QUEUE_CONNECTIONvariable in .env, it should be equal to "sync" (or set up your driver, like Redis if required).
By using "log" driver you should see your message in the log. If it works fine with "log" and doesn't work with smtp then you should get an error about it. If an error is present - please post it. If not - say so as well.
P.S. please note that if you're using php artisan serve, all variables from .env are updates only after restarting the php server.

How would you skip Laravel Scout if enviroment is not production?

I have an app that I am writing with Laravel. I am still fairly new with the framework and don't understand most of it. I am using Algolia as the search engine with Laravel's Scout. In the models you add use Searchable, a trait, and the records are automatically passed to Algolia, which is cool. I am trying to put a simple statement if (App::environment('local'))" exit scout, just so we are not sending our development data to Algolia. Scout will also throw an exception if I run out of the hacker level of 10,000 records a Algolia.
In your local .env add
SCOUT_DRIVER=null
In production add
SCOUT_DRIVER=algolia
In config/scout.php add
'driver' => env('SCOUT_DRIVER', 'null')
Automatically it will be ignored in local but work in production.
This is just a suggestion. Try to adapt it to your specific context.
On your local environment you can call YourModel::disableSearchSyncing(), which will prevent this model from pushing data to Algolia.
The reverse to this method is YourModel::enableSeachSyncing(), but the search is enabled by default, so usually there is no need to use it.
Per the Laravel 5.3 documentation:
Set the environment the in the .env file:
APP_ENV=local
Determine the current environment:
$environment = App::environment();
Check on $environment and return true:
if (App::environment('local')) {
// The environment is local
}
if (App::environment('local', 'staging')) {
// The environment is either local OR staging...
}
None of above solution works I suggest you to check in your toSearchableArray() method inside your User Model. If you try to set the SCOUT_DRIVER=null in local environment then you will face an error because your application tends to push to Algolia in any environment.
Try to do this instead:
public function toSearchableArray()
{
if (! app()->isLocal()) {
return [
'username' => $this->username,
'age' => (string) $this->age,
// and so on ...
];
}
}

Laravel 5.2: Update .env file with user input & run migrations through code

I'm creating an app and I am planning to give users a one click installation feature. The idea is to show a form when the application is first launched, sort of Installation / Configuration screen where user will type Database details (hostname, db name, username & password) and will enter user details (email, username and password for default admin account). Once he will submit the form, I want to do following tasks:
Update .env file with hostname, db name, username & password
Run all migrations
Run all db:seeds
Create a user based on user input (this is not much of an issue)
Is it possible to do via code? I have tried to google this but can't find any help.
As the title says, I'm using L5.2 for this project.
So here is the final solution after playing around with this.
My controller:
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Storage;
class TestController extends Controller
{
public function index() {
// Values I want to insert
$data = [
'APP_KEY' => str_random(32),
'DB_HOST' => 'localhost',
'DB_DATABASE' => 'lara_test',
'DB_USERNAME' => 'root',
'DB_PASSWORD' => ''
];
// default values of .env.example that I want to change
$defaults = ['SomeRandomString', '127.0.0.1', 'homestead', 'homestead', 'secret'];
// get contents of .env.example file
$content = file_get_contents(base_path() . '/.env.example');
// replace default values with new ones
$i = 0;
foreach ($data as $key => $value) {
$content = str_replace($key.'='.$defaults[$i], $key.'='.$value, $content);
$i++;
}
// Create new .env file
Storage::disk('root')->put('.env', $content);
// run all migrations
Artisan::call('migrate');
// run all db seeds
Artisan::call('db:seed');
dd('done');
}
}
New Disk Driver:
To create a new file at project root, I had to create a new Disk Driver. I added following code in my config/app.php file:
'disks' => [
.....
'root' => [
'driver' => 'local',
'root' => base_path(),
],
],
and this enabled me to create new file at root by using:
Storage::disk('root')->put('filename', $content);
Summary:
So basically I am getting the contents of .env.example file, changing the values of constants I want and then creating a new .env file. After that I ran all my migrations and seeds.
Note:
I had to manually set the APP_KEY because of a stupid error No supported encrypter found. The cipher and / or key length are invalid.
Since I am trying to do everything inside code, not through commands - I tried using Artisan::call('key:generate'); but for some strange reasons it didn't work so to fix the issue, I had to create a random string manually which is 32 bit long and set it as APP_KEY.
Hope this will help someone else. :)
And thanks to #rypskar for assistance.
Everything can be done using code ;)
You could write a sh script which you call from your code or you can do this directly from your code.
I haven't seen any functions for copying and populating .env file, but you could read .env.example using file_get_contents() and update the content before writing the new file back to disk.
\Illuminate\Support\Facades\Artisan::call('migrate');
\Illuminate\Support\Facades\Artisan::call('db:seed'); (Not tested since I only have done this from a test where it is possible to use $this->seed();
User::create(['column', => $value])

how to fix CConsoleApplication.user undefined in a command class in yii framework?

I am having that error , whenever I ran my simple cron script in shell ,
any idea how to fix that thing ?, from the error itself, it says the .user is undefiend,
when I placed the
'user' => array(
// enable cookie-based authentication
'allowAutoLogin' => true,
'loginUrl' => array('myaccount/blah/login'),
in the console config, it is looking for a "Class" ,, what class am i supposed to include in that array? , this user login url is using an LDAP stuff in loggin in and authentication, what should I do ?
A CConsoleApplication is for handling offline tasks. For example, the application starts a cronjob within a linux system. The application checks each day if a registered user of your website should change his password, because it must be changed every 3 month. If the password expired send an email.
To preselecting the users you have set a scope condition to check the status of a user, as well as a scope to restricted signed in users on her own data:
public function scopes(){
return array(...,
'user' => array(
'condition'=>'id='.Yii::app()->user->id,
),
'active' => array(
'condition'=>'status='.self::STATUS_ACTIVE,
), ...
);
}
Now, in your CCA-Code you use the active scope to get all users:
$usersArray = User::model()->active()->findAll(); ...foreach.... The Problem here is in the use of the extended class, the CActiveRecord-class. Mostly used as a class extension in models, which are stored in a database. In this CActiveRecord-class the CActiveRecord->__call function is used to get all stored scopes of a model. After that the class merged the actually requested scopes with the rest of the database criteria. The fact that all scopes are loaded first occures the error in loading the user-scope, include Yii::app()->user->id. The WebUser is called and throws the exception 'CException' with message 'attribute "CConsoleApplication.user is not defined'. You wouldn't call the WebUser, but the automatism arrange this for you :-)
So, do it like schmunk says. Generate in your scope code an exception part where ensures that Yii::app()->user is not called:
public function scopes(){
if (Yii::app() instanceof CConsoleApplication) {
$user = array(''); //no condition
}else{
$user = array(
'condition'=>'id='.Yii::app()->user->id,
);
}
return array(
'user' => $user,
'active' => array(
'condition'=>'status='.self::STATUS_ACTIVE,
), ...
);
}
I hope the explanation helps and perhaps also for other problems.
Short answer: You can't use CWebUser in console application. Don't include it in your config/console.php
Long(er) answer: If you rely on a component, which needs CWebUser, you'll have to detect this in the component and create some kind of workaround for this case. Have a look at this code piece for an example how to detect, if you're running a console app.
Try this
public static $console_user_id;
public function init() {
if (Yii::app() instanceof CConsoleApplication) {
if (self::$console_user_id) $this->id = self::$console_user_id;
return false;
}
parent::init();
}
solved my problem by using update, instead of save in the script...no need to use user array and CWebUser class
I had the same problem. Screened all answers given here and found some good point, but solved my problem my way, although it may not be the best.
First off all I had to figure out that my Cron Jon threw the aforementioned Exception because inside the Cron job I was running a script which had this part of code in it
if(Yii::app()->user->isAdmin()) {...} else {...}
So the console threw the error since the user was not defined. I changed my code in such a way that I tested if the console was running it. The changed code is as follows:
$console = false;
try {
$test = Yii::app()->user->isAdmin();
}
catch (CException $e) {
$console = true;
}
if($console || (!$console && Yii::app()->user->isAdmin()) {...} else {...}
As said, not perfect, but maybe a solution for someone.

Categories