Codeigniter does not find model files in models subfolders - codeigniter

Saving a model in a sub-folder such as models/cronjobs/Dbsconnection_model.php I always get a "Message: Unable to locate the model you have specified: Dbsconnection_model" error when i load it with
public function __construct()
{
parent::__construct();
require('application/config/CronJobs/CronjobsConfig.php');
**$this->load->model('cronjobs/dbsconnection_model');**
[......]
If i take the same model in the upper folder there are no troubles; in other words, this function
$this->load->model('dbsconnection_model');
does not trigger any error if the relative file is copied in the main models folder too. I tried also several combinations for the subfolder name:
cronjobs
Cronjobs
CronJobs
changing it both in the filesystem and in the loading function. Any ideas?

You need to capitalize the first letter of your model class and it will work.
So you can still call it like
$this->load->model('cronjobs/dbsconnection_model');
But the model file itself needs to start with a capital letter.
For example
application/models/cronjobs/Dbsconnection_model.php

Related

Get correct URL for uploaded files

I have a function in my platform for letting users upload their own icon images. Once they've uploaded them I save them using $request->icon->store('public/icons') and simply save the returned path, something like "public/icons/xa6y2am3e4cOdqQuLpvEhFSXDKwFMDOgggS2i67l.png".
I'm not really clear though on what's the correct way to show the icons. The URL for showing the icon in the above example is "/storage/icons/xa6y2am3e4cOdqQuLpvEhFSXDKwFMDOgggS2i67l.png", thus I need to replace "public" in the path with "storage", which makes me think I've done something wrong somewhere (I see no reason why the store() method should provide me with a path that's not correct).
I have done my symlinks as described in the documentation. Using the local storage. What am I missing?
This is how I handle my storage in one of my apps that includes blogs:
$storedImageName = $request->file('main_image')->store('blog_images', 'public');
The store method actually returns the stored file name along with the path. Here, I specify that my disk is public and that the folder inside public is blog_images. I store the result of that in $storedImageName.
Now, to save it in the database, I do not actually save the whole path, I save ONLY the image name. This is because, you may want to update your directory name in the future, or move it to another location, etc. You can get that like this:
$onlyImageName = basename($storedImageName);
basename() is PHP's function, has nothing to do with Laravel.
This way, I can render my images in my blade files like this:
<img ... src="{{ asset('/storage/blog_images/' . $blog->main_image) }}" />
asset() helper will provide you with path to your public directory, and then you just need to specify the rest of the path to your image.

Laravel: How to prevent users loading files from outside the base path

I have a Laravel website and I have several routes that load the contents of images from Storage. I do this using the following code:
public function show_image($name) {
echo Storage::disk('images')->get($name);
}
I want to prevent users being able to set name to something like ../../../error.log. So I don't want users to escape the Storage directory. I have a few ideas on how to accomplish this however I want to know is there a best practice?
If you need just file name, not location, disallow them from inputting folder of any kind. Just cut the string on /.
end(preg_split("#/#", $name));
When you need to allow some folders and all of the contents, check the folder name, subfolder name, etc.
You could either keep a registry/index of the uploaded images, and only allow the user to show a image from that registry (e.g. an images database table).
Or you could do a scan of the directory, that you are allowing files from, and make sure, that the requested file is in that list.
public function show_image($name) {
$files = Storage::disk('images')->files();
if (! in_array($name, $files)) {
throw new \Exception('Requested file not found');
}
echo Storage::disk('images')->get($name);
}
(code untested)

Two models, two fields, return preferred if present

Been struggling with how to do this the most optimized way possible...
I have two models: Catalog and Application.
Catalog has a field called name.
Application has a field called name.
Both have a relationship with each other.
I am struggling to find a way to create a function i could use across my Laravel application which i would pass application.id to it and it would return a $app->name value based on the following logic:
if $application->name exists, use this value as the $app->name for the $application object
otherwise, get the $catalog->name value and use it as the $app->name
Note that I would like to create a component #application() where i can simply pass the $application->id and build the display logic (theming/styling) into it.
Since i display this $app->name in many places, i would like to make it as lightweight as possible to avoid unnecessary queries.
I hope this makes sense! There are probably so many ways to go with it, i am lost at figuring out the way way to do this :(
I'm not completely sure to understand your model/DB design, but you could use a custom Helper to use that function through the whole app.
For that, you can create a simple PHP class Helper.php file in app/Http/Helpers folder or whatever location you want. Something like:
<?php
use App\Catalog;
use App\Application;
if (! function_exists('getAppName')) {
function getAppName($id){
// Do your logic here to return the name
$catalog = Catalog::find($id);
return $catalog->name;
}
}
?>
Then in any controller or view, you just do
getAppName($application->id)
Do no forget to add your helpers file to the composer autoload. So in composer.json in Laravel's root folder, add the helper path to the autoload array:
"files": [
"app/Http/Helpers/helpers.php"
],
Last but not least, run the following command:
composer dump-autoload
Please note that function logic is just for sample purposes since I don't know your model structure.
In my opinion, I care about the database cost.
Use ternary expression will be elegant. But it took two times IO costs from database if application name is empty.
$app_name = Application::find($id)->name;
$app_name = empty($app_name) ? Catalog::where('application_id', $id)->first()->name;
And this will more complicated, but the catalog_query only execute when application.name is empty, it execute in database and the result is taken out only once;
And Database will only find the name from one table or two table.
Something like this:
$catalog_query = Catalog::where('catalogs.application_id', $id)->select('catalogs.name')->groupBy('catalogs.name');
// if catalogs and applications relationship is 1:1, use ->limit(1) or remove groupBy('name') is better.
Application::where("applications.id", $id)
->selectRaw("IF(application.name IS NULL OR application.name = '', (" . $catalog_query->toSql() ."), applications.name ) AS app_name")
->mergeBindings($catalog_query->getQuery())
->first()
->app_name;
Hope this will help you.

composer autoload files and variables

I'm creating a class that gets a random string from an array. The data will not change enough to make using a database worth it, but there are a few hundred entries so I don't really want to put the entire thing, into the class I'm creating.
Is there a way I can use composers autoload files to create a new php file, dump the array in and use it where ever I like? I've read up and to do that you apparently need to use the globals keyword which I'd rather not do.
Am I thinking too much about this? Would you just add the array to the class, or do a require etc, the functionality of the class itself is tiny.
Thanks.
Lets say you have these strings as text file. If its composer package, you can use composer scripts and generate php file from this text file during installation.
Then you can have one class with your functionality and second class containing array of items only.
Items class generation can look like (not tested):
<?php
...
$items = file_get_contents('items.txt');
$fileContent = '<?php
namespace Your\Namspace;
class Items {
public function getItems() {
return [
\'' . implode("',\n\t\t\t'", array_filter(explode("\n", $items))) . '\'
];
}
}';
file_put_contents('Items.php', $fileContent);

Cakephp response (sending files) breaks when model functions are added

I have baked a File model and controller with default actions. Now I am trying to add an display function which can be used to show images in controlled manner.
I want to protect images so that display function can check does the user have an permissions to view image (image directory is not in a webroot).
I haven't been able to make it work, but when I started from the scratch I managed to find out that really minimal function did work.
Working function looks like this:
public function display($id) {
$this->response->file(ROOT.DS.'img'.DS.'noimage.jpg');
return $this->response;
}
When I add example:
$test=$this->File->findById($id);
to the starting of the function everything breaks.
--> http://www.example.com/files/display/1
The requested file /var/www/example.com/www/img/image.jpg was not found or not readable
Error: The requested address '/files/display/1' was not found on this server.
I have tried with debug zero, file can be found and is readable, obviously because the function without findById works.
Any ideas?
cakephp 2.4.3
You path is totally wrong.
Did you debug() what ROOT.DS.'img'.DS.'noimage.jpg' actually holds?
I bet all the money of the world that you would probably find the solution yourself if you did
The img folder is most likely in webroot
WWW_ROOT . 'img' . DS . 'noimage.jpg'
Note that paths usually end with a DS so no need to add it again.
So if it really is an image folder in ROOT:
ROOT . 'img' . DS . 'noimage.jpg'
Also note that you can easily check if a path is valid using
file_exists()
If the file has the correct file permissions this should return true.
EDIT:
$this->File->...: File is not a good choice for a model name as it collides with the existing core class in Utility. You need to be a little bit more creative with your model naming scheme.

Resources