I want to create vendor package in cakephp 3. It should depend on another package, that has both php files and some static assets: like js, css, img etc. Setting up php files autoloading I am able to handle. However to load static files from another vendor, e.g.
echo $this->Html->css('AnotherPackage.styles');
cake expects that they should be inside vendor's webroot directory, which they are not
# another package's files
/vendor/author/another-package/php
/vendor/author/another-package/css_files
/vendor/author/another-package/js_files
/vendor/author/another-package/images
Only similar issue I found is copying files to webroot , which is something I do not want to do.
How can I tell cake to load the vendor's files from their exact folders instead of webroot ? Or in what better way this problem can be solved, without being have to copy something. I am using composer.
Thanks
Are you doing this on a Linux box? If so, you could just create a symbolic link in order to have the webroot directory point right back at the root directory of the package.
Are you using composer?
Does the project you're working on depend on the vendor's package within your composer.json file?
If so, you could create a Controller (something like ExternalAssets) in your project that can read those vendors files, and pass them through to the Response object.
<?php
/**
* ExternalAssetsController
*/
namespace App\Controller;
use App\Controller\Controller\AppController;
use Cake\Core\App;
use Cake\Http\Exception\BadRequestException;
use Cake\Http\Exception\ForbiddenException;
use Cake\Routing\Router;
/**
* ExternalAssets Controller
*
* Serves up external assets that aren't in the webroot folder.
*/
class ExternalAssetsController extends AppController
{
/**
* Initialize method.
*
* #return void
*/
public function initialize()
{
parent::initialize();
$this->loadComponent('RequestHandler');
// see https://book.cakephp.org/3.0/en/development/routing.html#routing-file-extensions
// or whatever extensions you need.
Router::extensions(['css', 'js', 'png', 'jpg']);
// if you're using the auth component in a restricted way.
$authAllowedActions = ['asset'];
$this->Auth->allow($authAllowedActions);
}
/**
* Delivers an asset.
*
* #param string|null $folder The Folder's name.
* #param string|null $file The File's name.
* #return \Cake\Http\Response
* #throws \Cake\Http\Exception\BadRequestException When $folder or $file isn't set.
* #throws \Cake\Http\Exception\ForbiddenException When we can't read the file.
*/
public function asset($folder = null, $file = null)
{
if (!$folder) {
throw new BadRequestException(__('Folder was not defined'));
}
if (!$file) {
throw new BadRequestException(__('File was not defined'));
}
$folder = str_replace('..', '', $folder);
$file = str_replace('..', '', $file);
$basepath = realpath(ROOT . DS . 'vendor' . DS . 'author' . DS . 'another-package');
$path = realpath(ROOT . DS . 'vendor' . DS . 'author' . DS . 'another-package' . DS . $folder . DS . $file . '.' . $this->getRequest()->getParam('_ext'));
if (strpos($path, $basepath) === false) {
throw new ForbiddenException(__('Path out of bounds, possible hack attempt.'));
}
if (!is_readable($path)) {
throw new ForbiddenException(__('Unable to read the file.'));
}
$this->setResponse($this->getResponse()->withFile($path, [
'name' => $file . '.' . $this->getRequest()->getParam('_ext'),
'download' => false
]));
return $this->getResponse();
}
}
Then use Router::url() to create the compiled path to your controller.
Something like:
<link rel="stylesheet" href="<?=Router::url([
'prefix' => false,
'plugin' => false, // unless the controller in in a plugin
'controller' => 'ExternalAssets'
'action' => 'asset'
0 => 'css_files',
1 => 'css_file_name',
'_ext' => 'css'
]) ?>">
Related
Currently have working on an image upload in a Laravel/Inertia/React stack.
Issue: It currently works using a symbolic link to the public folder. This is no good as it means anyone can access the images if they have the link. How can I do this differently so that only the owner of the image can view it?
Displaying the image:
<img src={`/storage/${props.company.logo_filename}`}/>
Storing the logo:
public function storeLogo(Request $request)
{
$company = auth()->user()->company();
$logo = $request->file('logo');
$extension = $logo->getClientOriginalExtension();
Storage::disk('public')->put($logo->getFilename() . '.' . $extension, File::get($logo));
dd(Storage::url('public/'. $logo->getFilename()));
$company->logo_mime = $logo->getClientMimeType();
$company->logo_original_filename = $logo->getClientOriginalName();
$company->logo_filename = $logo->getFilename() . '.' . $extension;
$company->save();
//DELETE old Logo if exists
return Redirect::back()->with(
'message',
[
'type' => 'success',
'text' => 'Logo Updated'
]
);
}
note: In this particular scenario (company logos) I'm aware that it probably doesn't matter if someone else gets access to the images. Please just assume they are sensitive.
You could add a route to serve the files and check if the current user is allowed to access the file.
use Illuminate\Support\Facades\Storage;
Route::get('files/{filename}', function (string $filename) {
// Do your magic to check if the current user is allowed to access that file
// Do your magic to determine the full path of the file
$fullPath = '/some/directory/' . $filename;
// Once we have the full path we can stream the contents of the file to the client
return Storage::response($fullPath);
});
Unfortunately the Storage::response() method is undocumented as far as I know, but you can find it's implementation here:
https://github.com/laravel/framework/blob/5.5/src/Illuminate/Filesystem/FilesystemAdapter.php
I have been at this for a couple days now. Seems like the simplest thing in the world but for the life of me I cannot get this to work.
I am trying to use this class in my Controller:
https://github.com/neitanod/forceutf8
The class is named Encoding.php and it has a namespace ForceUTF8.
I've tried all of the following:
App::uses('Encoding','Vendor'); //(copying Encoding.php directly in the Vendor dir)
App::uses('Encoding','Vendor/ForceUTF8'); //(copying Encoding.php in ForceUTF8 subdir)
App::uses('Encoding’,’Lib'); //(copying Encoding.php directly in the Lib dir)
App::uses('Encoding’,’Lib/ForceUTF8'); //(copying Encoding.php in ForceUTF8 subdir)
require_once(APP . 'Vendor' . DS . 'Encoding.php'); //(use plain old php require_once to load class from Vendor dir)
No matter what I do I get the same error: Class 'Encoding' not found.
I find the CakePHP documentation to be very confusing on this subject. On the one hand it says not to use App::uses for non-CakePHP classes because the classes might not follow CakePHP standards. Fair enough. So instead they say to use App::import. But then there are tons of posts saying that App::import is nothing more than a wrapper for require_once.
So after not being able to get App::uses or App::import to work, I tried require_once. Same error. Then I found a post here on so saying even when using require_once, you still have to 'initialize' the class in order to CakePHP to be able to see/use it. And how is that done? App::uses. So I'm back where I started.
Something tells me the namespace is causing the problem. When I use require_once the class is found (I'm pretty sure) because, for example, if I change
require_once(APP . 'Vendor' . DS . 'Encoding.php');
to
require_once(APP . 'Vendor' . DS . 'blabla.php');
it gives me an error, file not found.
But even though require_once seems to find it, CakePHP still says class not found.
How can I load a namespaced vendor file?
In Cakephp 2.x, follow following steps
at top of class file add
use \Dropbox as dbx;
[Dropbox is vendor directory in my case]
use \Dropbox as dbx;
App::build(array('Vendor/Dropbox' => array('%s' . 'Dropbox' . DS)), App::REGISTER);
// Autoload the classes in the 'vendors'
spl_autoload_register(function ($class) {
foreach (App::path('Vendor') as $base) {
$path = $base . str_replace('\\', DS, $class) . '.php';
if (file_exists($path)) {
include $path;
return;
}
}
});
Now call your class method.
Cake2.x does not support namespaces so you need write your own loader
spl_autoload_register(function ($class) {
foreach (App::path('Vendor') as $base) {
$path = $base . str_replace('\\', DS, $class) . '.php';
if (file_exists($path)) {
include $path;
return;
}
}
});
more info here:
http://www.dereuromark.de/2012/08/06/namespaces-in-vendor-files-and-cake2-x/
Base on this article:
http://www.dereuromark.de/2012/08/06/namespaces-in-vendor-files-and-cake2-x/comment-page-1
I'm using the paypal sdk. And this is my code.
In bootstrap.php:
// Add 'vendors' as sub-package of 'Vendor' to the application
App::build(array('Vendor/vendors' => array('%s' . 'vendors' . DS)), App::REGISTER);
// Autoload the classes in the 'vendors'
spl_autoload_register(function ($class) {
foreach (App::path('Vendor/vendors') as $base) {
$path = $base . str_replace('\\', DS, $class) . '.php';
if (file_exists($path)) {
include $path;
return;
}
}
});
In the PaypalComponent:
use PayPal\Rest\ApiContext;
use PayPal\Auth\OAuthTokenCredential;
Use those classes in function:
$this->apiContext = new ApiContext(
new OAuthTokenCredential()
);
I am in a problem with CakePDF. I am using CakePHP 2.3.6. I setup everything alright, bootstrap & core files are ok.
Now, I want to generate many pdf files and download them. Downloading is ok, but when I download the files, I see that the generated pdf files say that Undefined $data, where I send $data to the view file.
Here is my Controller code:
App::uses('CakePdf', 'CakePdf.pdf');
// ...
public function createPdf($id) {
$data = $this->DBTable->find('all', array(
'conditions' => array(
'DBTable.id' => $id
)
));
$CakePdf = new CakePdf();
$path = APP . DS . 'pdf' . DS;
foreach($data as $key => $var) {
$CakePdf->template('create', 'default');
$this->set('var', $var);
$this->pdfConfig = array(
'orientation' => 'portrait',
'filename' => $var['id'] . ".pdf"
);
$CakePdf->write($path . $var['id'] . ".pdf");
}
}
Here, I am downloading the files some other way, not related to this problem, because downloading is ok. When I run this, all files are downloaded, and when I see the files, they say "Udefined var", looks like they didn't receive and variable called "$var".
I put the view file & the layout exactly where ceeram said.
What should I do now ? Please help me.
At last I got a solution to this. In the Controller function :
$data=$this->ModelName->find('all');
$CakePdf=new CakePdf();
$CakePdf->template('view_file','default');
$this->pdfConfig=array('orientation'=>'portrait','filename'=>$data['name']);
$CakePdf->viewVars(array('data'=>$data));
$CakePdf->write($path.$data['name'].".pdf");
Here, we have to store view_file.ctp in View/Pdf/, and default in View/Layouts/pdf/, where view_file.ctp is the view file which we want to convert in pdf, and default is the layout for this specific view file.
Here, viewVars() function passes the data to the view file, just like :
$this->set->('data',$data);
Let me know if anything is not clear here.
Thanks.
How to log all database updates, inserts or deletes in CakePHP made using pure SQL?
example:
$this->Car->query('update cars set color = "red" ');
Extend whatever datasource you're using and override the _execute()
method to log and pass back to the parent.
For example, let's assume you're currently using dbo_mysql. That means
your db config is something like this:
class DATABASE_CONFIG {
var $default = array(
'driver' => 'mysql',
// ...
)
}
so change 'driver' to 'mysql_with_log', and create the file app/model/
datasources/dbo/mysql_with_log.php :
<?php
require (LIBS . 'model' . DS . 'datasources' . DS . 'dbo' . DS .'dbo_mysql.php');
class DboMysqlWithLog extends DboMysql {
function _execute($sql) {
$this->log($sql);
return parent::_execute($sql);
}
}
?>
Here is the Reference link.
You can also use Cake debug kit.
This plugin will also help you to save SQL Logs. Here is the link to download Debug Kit.
I'm new to cakephp and I have found this milesjohnson's upload plugin ,
and I kind of like it, mostly because it gives me the chance of renaming the file once uploaded.Unfortunately, I can't get it to upload any zip/rar files.
This is the action where I upload the file:
function add() {
if (!empty($this->data)) {
if ($data = $this->Uploader->upload('link_referencia', array('name' => date("dmYhis")))) {
debug($data);
$this->data['Publicacione']['link_referencia']=$data['name'];
}
$this->Publicacione->create();
if ($this->Publicacione->save($this->data)) {
$this->Session->setFlash(__('The publicacione has been saved', true));
//$this->redirect(array('action' => 'index'));
} else {
$this->Session->setFlash(__('The publicacione could not be saved. Please, try again.', true));
}
}
$users = $this->Publicacione->User->find('list');
$this->set(compact('users'));
}
And this is the error I get everytime I attempt to upload any zip/rar file :
EDIT
Full insert query:
INSERT INTO `publicaciones` (`vigencia`, `tipo`, `titulo`, `descripcion`, `fecha_publicacion`, `fecha_caducidad`, `link_referencia`, `modified`, `created`) VALUES (1, 'c', 'there\'s nothing you can\'t do', '
fsdfsdfsdf
', '2011-06-07', '2011-06-30', Array, '2011-06-07 16:47:23', '2011-06-07 16:47:23')
Does anyone have any ideas on what the problem might be?
Thanks in advance.
i think there is nothing with the code what you have written but you should look at in to the plugin and find out whether it gives permission you to upload zip or not.
there will be conditions in your pluggin that you can upload only some kind of files like jpg,png,txt something like that.
I hope that helps you.
Regards,
Archit
Are you totally sure your File input on the form has type=>file specified, and same for your form?
Also I would look at other uploaders - MeioUpload can allow renaming and so on and is a bit more up to date. There is also the Cuploadify plugin (uploadify for cake) you can find on github.
Make sure your form is set to multipart/form-data like so:
<?php echo $this->Form->create('File', array('enctype' => 'multipart/form-data')); ?>
The following code will upload a file:
if ($this->request->is('post')) {
if ( $this->data['File']['file']['error'] <= 0 && $this->data['File']['file']['size'] <= 8388608 ) { // Check for no errors and that File size is around 8mb.
$folder = new Folder (ROOT . DS . 'app' . DS . 'filestorage' . DS, true); // create folder in /app/filestorage/
$path = $folder->path . $this->data['File']['file']['name']; // Set path to newly created folder + uploaded file name.
$tmpUrl = new File ( $this->data['File']['file']['tmp_name'] ); // Create temporary file object
if ($tmpUrl->copy($path , true) ) { // If copying file to path is successful,
$this->Session->setFlash(__('File uploaded succesfully!'));
}
}