Laravel 5.5: File download FileNotFoundException? - php

I'm building a projectmanagement system, where users can upload file attachments to tasks. These attachments are stored in directory 'storage/app/public/projects//'. Uploading works like it should, in the right directory under the right ID.
However when I want to download said attachment, somehow the file can't be found. I've provided the code from my up- and download methods, as well as my 'local' driver configuration.
Driver configuration:
'local' => [
'driver' => 'local',
'root' => storage_path('app/public'),
'url' => env('APP_URL').'storage'
],
Upload method:
$sExt = $request->file('attachment')->getClientOriginalExtension();
$sHashedName = substr(
sha1(str_replace(' ', '', pathinfo($request->file('attachment')->getClientOriginalName(), PATHINFO_FILENAME))
), 0, 14);
if ( ! Storage::disk('local')->exists($sHashedName . '.' . $sExt)) {
$request->file('attachment')->storeAs(
'/projects/'.$oTask->project->id, $sHashedName . '.' . $sExt, 'local'
);
}
$oTask->attachments()->create([
'name' => $request->name,
'location' => $sHashedName . '.' . $sExt,
'user_id' => Auth::id()
]);
Current download method:
public function downloadAttachment(Project $project, Task $task, Attachment $attachment)
{
var_dump(rtrim(env('APP_URL'), '/') . public_path('/projects/' . $project->id . '/' . $attachment->location));
if (rtrim(env('APP_URL'), '/') . public_path('/projects/' . $project->id . '/' . $attachment->location)) {
return response()->download(rtrim(env('APP_URL'), '/') . public_path('/projects/' . $project->id . '/' . $attachment->location));
} else {
return $this->redirectWithAlert(
'error',
'download',
'attachment',
$attachment->name,
'/projects/'.$project->id.'/tasks/'.$task->id
);
}
}
This was my last attempt before posting this question. I have also tried Storage::url('/projects/<project_id>/<filename>') and a number of other things, but none work. I have linked a public storage directory according to the Laravel docs (with php artisan storage:link). I'm probably missing something logical here, but I'm completely lost.

The public_path function refers to ./public/, and not the storage disk 'public' that can be found in ./storage/app/public/
One way of solving this would be to replace public_path('/projects/' with storage_path('app/public/projects/'

Related

How to fix Sometimes happen 500 error in Laravel

I have done configurations to fetch data from database and assign corresponding to it.
It works Fine. but sometimes issues happen like undefined index or target class not found.if i refresh again issues not happen that time.
Note: sometimes happens only. so i can't find what exact issue.
AppserviceProvider in boot method i call below function
public function CustomInit(){
if (env('DB_DATABASE') != '') {
// Configuration Setup for Email Settings
if (Schema::hasTable('email_settings')) {
$result = DB::table('email_settings')->get();
$mail_config = array(
"default" => $result[0]->value,
"from" => [
"address" => $result[3]->value,
"name" => $result[4]->value
],
"mailers" => [
"smtp" => [
'transport' => 'smtp',
"host" => $result[1]->value,
"port" => $result[2]->value,
"encryption" => $result[5]->value,
"username" => $result[6]->value,
"password" => $result[7]->value,
'timeout' => null,
],
]
);
Config::set('mail',$mail_config);
$site_settings = SiteSettings::all();
Config::set(
[
'laravel-backup.backup.name' => $site_settings[0]->value,
'laravel-backup.monitorBackups.name' => $site_settings[0]->value,
'laravel-backup.notifications.mail.from' => $result[3]->value,
'laravel-backup.notifications.mail.to' => $result[3]->value,
]
);
}
if (Schema::hasTable('site_settings')) {
$site_settings = DB::table('site_settings')->get()->pluck('value', 'name');
$rand = str_random(6);
if ($site_settings['site_url'] == '' && $_SERVER['HTTP_HOST']) {
$url = "http://" . #$_SERVER['HTTP_HOST'];
$url .= str_replace(basename($_SERVER['SCRIPT_NAME']), "", #$_SERVER['SCRIPT_NAME']);
SiteSettings::where('name', 'site_url')->update(['value' =>$url]);
}
if (!#$_SERVER['HTTP_HOST']) {
Config::set('app.url', $site_settings['site_url']);
URL::forceRootURL($site_settings['site_url']);
}
View::share("site_name", $site_settings['site_name']);
View::share("version", $site_settings['version']);
View::share("version", str_random(4));
View::share('favicon', url('logos/' . $site_settings['favicon'] . '?v=' . $rand));
View::share('logo_web_1', url('logos/' . $site_settings['logo_web_1'] . '?v=' . $rand));
View::share('logo_web_2', url('logos/' . $site_settings['logo_web_2'] . '?v=' . $rand));
View::share('email_logo', url('logos/' . $site_settings['email_logo'] . '?v=' . $rand));
View::share('web_favicon', url('logos/' . $site_settings['favicon'] . '?v=' . $rand));
define('SITE_NAME', $site_settings['site_name']);
define('LOGO_URL', url('logos/' . $site_settings['logo_web_1'] . '?v=' . $rand));
define('EMAIL_LOGO', url('logos/' . $site_settings['email_logo'] . '?v=' . $rand));
define('FAV_ICON', url('logos/' . $site_settings['favicon'] . '?v=' . $rand));
}
if (Schema::hasTable('join_us')) {
$join_us = DB::table('join_us')->get()->pluck('value', 'name');
View::share("app_store", $join_us['app_store']);
View::share("play_store", $join_us['play_store']);
}
if (Schema::hasTable('api_credentials')) {
// For Google Key
$google_map_result = DB::table('api_credentials')->where('site', 'GoogleMap')->get();
define('MAP_KEY', $google_map_result[0]->value);
define('MAP_SERVER_KEY', $google_map_result[1]->value);
View::share('map_key', $google_map_result[0]->value);
// For TWILLO Key
$twillo_result = DB::table('api_credentials')->where('site', 'Twillo')->get();
define('TWILLO_SID', $twillo_result[0]->value);
define('TWILLO_TOKEN', $twillo_result[1]->value);
define('TWILLO_FROM', $twillo_result[2]->value);
// For TWILLO Key
$fcm_result = DB::table('api_credentials')->where('site', 'FCM')->get();
Config::set(
['fcm.http' => [
'server_key' => $fcm_result[0]->value,
'sender_id' => $fcm_result[1]->value,
'server_send_url' => 'https://fcm.googleapis.com/fcm/send',
'server_group_url' => 'https://android.googleapis.com/gcm/notification',
'timeout' => 10,
],
]
);
}
$current_route = url()->current();
if (Route::current()) {
$current_route = Route::current()->uri();
}
View::share('current_route', $current_route);
}
}
Thanks in Advance...
Short answer is don't try and read the .env file in your controller, retrieve the values through a corresponding config file instead.
Long answer - since Laravel 5.2.0 "if you use the config:cache command during deployment you MUST make sure you are only calling the env function from within your configuration files, and not from anywhere else in your application" - https://laravel.com/docs/5.2/upgrade#upgrade-5.2.0
In the code you've cited you're calling the .env file direct with :
if (env('DB_DATABASE') != '') {
Depending on which driver you're using, instead you want to retrieve this through the config/database.php file :
if(config('database.mysql.database' != '') {
That will provide a more stable method of retrieving the relevant value so you can see if it is empty or not.

My update function doesn't set values to null after saving

I received help to solve how to delete files uploaded by using the Cakephp Upload package. However, there seems to be a problem with how I update the values of the photo and dir fields. By using unlink I was able to delete the files perfectly, but there seems to be a problem when I try to set the values to null. I made a function to test it out:
public function deletePhoto2($id)
{
// $this->request->allowMethod(['post']);
if ($this->request->is(['patch', 'post', 'put'])) {
$brigada = $this->Brigadas
->findById($id)
->firstOrFail();
$brigada->dir = null;
$brigada->photo = null;
if ($this->Brigadas->save($brigada)) {
$this->Flash->success(__('Your team data has been saved.'));
return $this->redirect(['action' => 'edit', $brigada->id]);
}
$this->set('brigada', $brigada);
}
}
Before saving I find that the value of $brigada->photo and $brigada->dir are null, but values don't save. I have several possibilities that want to explore but my knowledge of PHP is a hindrance:
I may be doing updates wrong. Link
I may need to use the deleteCallback which is documented here, but I don't know how to do it. I figured that it would be with $this->Brigadas->deleteCallback() or something similar, but I'd like to understand an example first, which is why I'm asking. I found no use of these callbacks in any example on the web, and the documentation on events is still a bit esoteric for me.
Here is how BrigadasTable.php is setup to upload files:
// http://josediazgonzalez.com/2015/12/05/uploading-files-and-images/
$this->addBehavior('Josegonzalez/Upload.Upload', [
'photo' => [
'fields' => [
'dir' => 'dir',
'size' => 'photo_size', // defaults to `size`
'type' => 'photo_type', // defaults to `type`
],
'nameCallback' => function ($table, $entity, $data, $field, $settings) {
if ($entity->gvCode){
$array = explode(".", $data['name']);
return strtolower($entity->gvCode) . '_' . date("Ymd-hisa") . '.jpg';
} else{
$array = explode(".", $data['name']);
$newArray = array_pop($array);
return strtolower(join('_', $array)) . '_' . date("Ymd-hisa") . '.jpg';
}
},
'transformer' => function ($table, $entity, $data, $field, $settings) {
$extension = pathinfo($data['name'], PATHINFO_EXTENSION);
// Store the thumbnail in a temporary file
$tmp = tempnam(sys_get_temp_dir(), 'upload') . '.' . $extension;
// Use the Imagine library to DO THE THING
$size = new \Imagine\Image\Box(640, 640);
$mode = \Imagine\Image\ImageInterface::THUMBNAIL_INSET;
$imagine = new \Imagine\Gd\Imagine();
// Save that modified file to our temp file
$imagine->open($data['tmp_name'])
->thumbnail($size, $mode)
->save($tmp);
$filenameTmp = explode('.', $data['name']);
array_pop($filenameTmp);
$filenameTmp = join('_', $filenameTmp) . '.jpg';
// return debug($filenameTmp);
// Now return the original *and* the thumbnail
return [
$data['tmp_name'] => $filenameTmp,
$tmp => 'thumbnail-' . $filenameTmp,
];
},
'deleteCallback' => function ($path, $entity, $field, $settings) {
// When deleting the entity, both the original and the thumbnail will be removed
// when keepFilesOnDelete is set to false
$entity->{$field} = null;
return [
$path . $entity->{$field},
$path . 'thumbnail-' . $entity->{$field}
];
},
'keepFilesOnDelete' => false
]
]);
Thank you!
You can run an update query straight, instead of fetching the record, setting values and saving it.
$query = $this->Brigadas->query();
$query->update()
->set([
'dir' => null,
'photo' => null,
])
->where(<condition>)
->execute();
Incase any of your columns are json,
$query = $this->Brigadas->query();
$query->update()
->set([
'dir = null',
'photo' => null,
])
->where(<condition>)
->execute();

Laravel Scout and Elastic Search Don't Work in Tests

I have elastic search working when not in a testing environment. However when I create a model in a test for some reason it does not work. I have tried running it with the queue and without the queue. I can see that the job gets created and that the job runs before making the call. However, I am able to pull things that are already in the database in the test code. Any ideas why it would not work in testing?
This is my test code
$user = $this->newLoggedInUser();
$invoice = factory(App\Invoice::class)->create(['account_id' => $user->account_id]);
$this->get($this->url() . '?q=' . $invoice->title, $this->userAuthHeader($user))
->seeJson([
'Title' => 'Invoice: ' . $invoice->number . ($invoice->title ? ' - ' . $invoice->title : ''),
'Description' => 'Customer: ' . $invoice->customer->name,
'Type' => 'Invoice',
])
->assertResponseStatus(200);
I found that I had to add a slight delay to the get call as the index was not updated before the call was made. So I added sleep(1) and that fixed it. Also, I found that it is best to specify a separate index for the testing environment in the config.
$user = $this->newLoggedInUser();
$invoice = factory(App\Invoice::class)->create(['account_id' => $user->account_id]);
sleep(1);
$this->get($this->url() . '?q=' . $invoice->title, $this->userAuthHeader($user))
->seeJson([
'Title' => 'Invoice: ' . $invoice->number . ($invoice->title ? ' - ' . $invoice->title : ''),
'Description' => 'Customer: ' . $invoice->customer->name,
'Type' => 'Invoice',
])
->assertResponseStatus(200);

PHP Script not proceeding ahead with Amazon S3 Upload

I am trying to upload a file to the Amazon S3 using the AWS PHP SDK but whenever I try uploading, the script gives output till the PutObject operation but no output after that operation. I am not even able to dump the result object. The credentials are stored in the .aws in the root folder of my test machine (running Ubuntu). Below is the code -
$s3 = new Aws\S3\S3Client([
'version' => 'latest',
'region' => 'us-east-1'
]);
echo "<br />".realpath(UPLOAD_DIR . $apiKEY . "/" . $name);
try {
$result = $s3->putObject([
'Bucket' => 'quicklyusercannedspeechbucket',
'ContentType' => 'text/plain',
'Key' => $apiKEY . "/" . $name,
'SourceFile' => realpath(UPLOAD_DIR . $apiKEY . "/" . $name)
]);
var_dump($result);
}
catch(\Aws\S3\Exception\S3Exception $e) {
echo $e->getAwsErrorCode();
}
echo "Finished";
var_dump($result);
When I run the above code, I don't get any output for the $result array. Any idea what might be happening?
Any help is appreciated ^_^
-Pranav
Use below code to view if your image is uploaded successfully
try {
$result = $s3->putObject([
'Bucket' => 'quicklyusercannedspeechbucket',
'ContentType' => 'text/plain',
'Key' => $apiKEY . "/" . $name,
'SourceFile' => realpath(UPLOAD_DIR . $apiKEY . "/" . $name)
]);
$s3file='http://quicklyusercannedspeechbucket.s3.amazonaws.com/'.$name;
echo "<img src='$s3file'/>";
echo 'S3 File URL:'.$s3file;
var_dump($result);
}
catch(\Aws\S3\Exception\S3Exception $e) {
echo $e->getAwsErrorCode();
}
You can get step by step detail from here Amazon S3 File Upload Using PHP
It seems that I had put the credentials in the wrong folder. As per the NGINX, the default folder for storing the credentials was /var/www rather than the home directory of the user.
Also, I turned on the display_errors in the php.ini which helped me find that the AWS SDK was having problems with the credentials.
Thanks!

\Zend\File\Transfer\Adapter\Http() and filerenameupload

I'm trying to use the 'filerenameupload' filter with \Zend\File\Transfer\Adapter\Http():
$adapter = new \Zend\File\Transfer\Adapter\Http();
$adapter->addFilter('filerenameupload', array(
'target' => BASE_DIR . DIRECTORY_SEPARATOR . 'public' . DIRECTORY_SEPARATOR .
'img' . DIRECTORY_SEPARATOR . 'gallery' .
DIRECTORY_SEPARATOR . 'image.jpg',
'randomize' => true,
));
var_dump($adapter->isValid()); // true
if (!$adapter->receive()) {
$messages = $adapter->getMessages();
echo implode("\n", $messages);
}
Always having the error,
File '/tmp/somefile.png' could not be renamed. An error occurred while processing the file.
/tmp/somefile.png - exists, is readable an writable, distention folder too is readable an writable
Error comes from class RenameUpload:
protected function moveUploadedFile($sourceFile, $targetFile)
{
ErrorHandler::start();
$result = move_uploaded_file($sourceFile, $targetFile);
$warningException = ErrorHandler::stop();
if (!$result || null !== $warningException) {
throw new Exception\RuntimeException(
sprintf("File '%s' could not be renamed. An error occurred while processing the file.", $sourceFile), 0, $warningException
);
}
return $result;
}
So maybe someone have an example or know how to fix this error? Or what I'm doing wrong?
Thanks for #hemangpatel from #zftalk for advice, so the working action looks like:
public function uploadAction()
{
$adapter = new \Zend\File\Transfer\Adapter\Http();
$adapter->setDestination(BASE_DIR . DIRECTORY_SEPARATOR . 'public' . DIRECTORY_SEPARATOR .
'img' . DIRECTORY_SEPARATOR . 'gallery' . DIRECTORY_SEPARATOR);
// Returns all known internal file information
$adapter->addFilter('File\Rename', array('target' => $adapter->getDestination() .
DIRECTORY_SEPARATOR . rand(2, 10) . '.jpeg',
'overwrite' => true));
if (!$adapter->receive()) {
$messages = $adapter->getMessages();
return new ViewModel(['messages' => $messages]);
} else {
$this->flashMessenger()->addSuccessMessage('Upload success');
$this->redirect()->toRoute('admin', ['controller' => 'gallery',
'action' => 'index']);
}
}

Categories