Yii2: Finding file and getting path in a directory tree - yii2

I'm trying to search for a single filename in a bunch of directories and returning its path. I thought FileHelper::findFiles() would be a helping hand but it seems it doesn't accept a filename to search for but just a particular root directory and then it returns an array of found filenames.
Anyone who knows another Yii2 helper to accomplish this?

You should simply try:
$files = yii\helpers\FileHelper::findFiles('/path', [
'only' => ['filename.ext'],
'recursive' => true,
]);
Read more here.

You can do it easy on "pure" PHP
/**
* #var $file SplFileInfo
*/
$path = '/path';
$dirIter = new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::SKIP_DOTS);
$files = new RecursiveIteratorIterator($dirIter, RecursiveIteratorIterator::SELF_FIRST);
foreach ($files as $file) {
if ($file->isFile() === true && $file->getFilename() === '.htaccess') {
var_dump($file->getPathname());
}
}

Related

how to solve File upload validation problem in yii2

I'm trying to upload a file in yii2, the same code was working fine before but for some reason i can't figure out it stopped working after a lot of checks i notice the validate method of upload model is returning false and in the error message it says Array ( [file] => Array ( [0] => Only files with these extensions are allowed: png, jpg,jpeg,gif,pdf. ) ) but the most weird thing is i uploaded a jpg file i also try to upload a png file the same error, when i remove the check for extension in the model rules it works fineor totally remove the validation is also work, i don't know what am missing here any help would be appreciated.
NOTE //with the validation or the extension check for extension in place the codes in the if()
statement fails to execute but rather the else statement execute, removing the validation or the
extension check the code in if() works fine
class Upload extends Model
{
public $file;
public $randomCharacter;
public $fileDirectory;
public function rules()
{
return[
[['file'], 'file', 'skipOnEmpty' => false,'maxSize'=>1024 * 1024 * 2, 'extensions'=> ['png, jpg,jpeg,gif,pdf']],
];
}
public function upload($uploadPath=NULL)
{
if(isset($uploadPath) && $uploadPath !==NULL){
$filePath = $uploadPath;
}else{
$filePath = "#frontend/web/uploads/";
}
//generate random filename
$rand = Yii::$app->security->generateRandomString(10). '_' . time();
//assign generated file name to randomCharacter property
$this->randomCharacter = $rand;
//define the upload path;
if ($this->validate()){
$path = \Yii::getAlias($filePath);
$this->fileDirectory = $this->randomCharacter .'.'.$this->file->extension;
echo $path.$this->fileDirectory;
exit;
$this->file->saveAs($path.$this->fileDirectory );
return true;
}else{
// return false;
//with validation in place the else statement in executed
print_r($this->getErrors());
exit;
}
}
}
Remove the straight brackets of attribute "extensions"
Instead of:
[['file'], 'file', 'skipOnEmpty' => false,'maxSize'=>1024 * 1024 * 2, 'extensions'=> ['png, jpg,jpeg,gif,pdf']],
You should have this:
[['file'], 'file', 'skipOnEmpty' => false,'maxSize'=>1024 * 1024 * 2, 'extensions'=> 'png, jpg, jpeg, gif, pdf'],

How to insert name of image from folder in database (name to be the same)

I want to have the same name of image in database and in the image folder one I move. In folder is work but in database don't have ideas, can someone help me! Thanks
public function postRegister(Request $request) {
request()->validate([
'email' => 'required',
'password' => 'required|min:8',
'fullname'=>'required',
'birthday'=>'required',
'country'=>'required',
'address'=>'required|min:10',
'image' => 'required|image|mimes:jpeg,png,jpg,gif|max:2048',
]);
$image = $request -> file('image');
$destination = base_path().'/public/img';
$file_name = rand(100,1).date('h-i-s');
$image->move($destination, $file_name.".".$image->getClientOriginalExtension());
$data = $request->all();
// dd($image);
$check = $this->create($data);
return Redirect::to("login")->withSuccess('Great! You have Successfully loggedin');
}
If you want to set your image name to your db record.
Pass it to your $data before calling create method.
public function postRegister(Request $request) {
....
$data = $request->all();
$data['imageName'] = $file_name.".".$image->getClientOriginalExtension();
$check = $this->create($data);
return Redirect::to("login")->withSuccess('Great! You have Successfully loggedin');
}
If you want use mass assignment for save data you can use YourModelName::create(data).but you should pay attention to 2 thing .
first one define all fillable fields that you want allow to assign mass in your model class.so you should add your imageName field in fillable array .
second you should append yourImageName to your data that assign mass.like :data['yourImageField']=setvalue.
But if you want to assign row by row(its more safe and better i think) you should do like this: modelObject->Imagefield="imageName" and at end modelObject->save().

CakePHP 3 - Can't return proper json when debug mode = true

I'm new to stackoverflow, and I've just started to play around with CakePHP 3.
I've run into a weird problem:
I'm sending an ajax-request (form submit) to the controller, and I expect to get a proper json-response back. It works fine when I set debug mode to false in config/app.php, but when it's set to true, I get an error-message in the browsers console, and the responsetext seem to be html. I'm calling the action with the .json extension in the url.
I've linked screenshot of the console where the first response is with debug mode set to false, and the second set to true:
I have enabled the extensions in config/routes.php:
Router::scope('/', function (RouteBuilder $routes) {
$routes->extensions(['json', 'xml']);
(...)
Here's the controller-code:
public function getUserStats() {
$this->log($this->request->data, 'debug');
if (($this->request->is('post'))) {
$this->log('getCategories(): Post-request is received.', 'info');
$usersTable = TableRegistry::get('Users');
$q = $usersTable->find('statsByUsers', $this->request->data);
$users = $q->all();
// Calculating total amount per user.
foreach ($users as $u) {
foreach ($u->purchases as $p) {
$u->total += $p->total;
}
}
$this->log($users, 'debug');
$this->set('users', $users);
$this->set('_serialize', ['users']);
}
}
Here's the model code:
public function findStatsByUsers(Query $query, array $options) {
debug($options);
$options['dates'] = $this->getConvertedDates($options);
$query
->contain([
'Purchases' => function($q) use($options) {
return $q
->select(['id', 'total' => 'amount * count', 'purchase_date', 'user_id'])
->where(['purchase_date BETWEEN :fromDate AND :toDate',])
->bind(':fromDate', $options['dates']['fromDate'], 'datetime') // Binds the dates to the variables in where-conditions
->bind(':toDate', $options['dates']['toDate'], 'datetime');
}
])
->where([
'Users.id IN ' => $options['users'],
'Users.active' => true
]);
return $query;
}
I hope I've given you enough information so that you can help me solve this.
CakePHP version: 3.3.2
Looking at the bit of output that is visible in the screenshot
<div class="cake-debug-output"> ...
that HTML is output generated by the debug() function.
Look closely at your model code, and you should spot the call to the function. Remove it, and you should be good.
btw, the source of the call can be found in the first <span> element in the <div>, so if you experience similar problems in the future make sure to check that.
<?php
use Cake\Core\Configure;
// your class ,...
public function getUserStats() {
$this->log($users, 'debug');
Configure::write('debug',false); // DISABLE
$this->set('users', $users);
$this->set('_serialize', ['users']);
}

Yii2: finfo_file(C:\xampp\tmp\php29C.tmp): failed to open stream: No such file or directory

Getting error finfo_file(C:\xampp\tmp\php29C.tmp): failed to open stream: No such file or directory while uploading multiple files.
tried inserting $model->save(); before saveAs() but then it upload only one file not all files, also not getting path in database for each file which is getting uploaded.
Controller:
public function actionCreate()
{
$model = new RoomTypes();
if ($model->load(Yii::$app->request->post()))
{
$imageName = $model->room_type;
$model->file = UploadedFile::getInstances($model, 'file');
foreach ($model->file as $file_instance)
{
$model->save();
$file_instance->saveAs('uploads/room_img/' . $file_instance->baseName . '.' . $file_instance->extension);
//save the path in the db column
$file_instance->$model->images = 'uploads/room_img/'.$imageName.'.'.$file_instance->extension;
return $this->redirect(['view', 'id' => $model->id]);
}
}
else
{
return $this->render('create',
[
'model' => $model,
]);
}
}
It is possible that I already have answered this here within the last update after your comments but I'll add a different answer here as it is one more different issue beside the others. This error is thrown when using $file_instance->baseName or $file_instance->extension after saving the file. saveAs() whish its content is the following :
public function saveAs($file, $deleteTempFile = true)
{
if ($this->error == UPLOAD_ERR_OK) {
if ($deleteTempFile) {
return move_uploaded_file($this->tempName, $file);
} elseif (is_uploaded_file($this->tempName)) {
return copy($this->tempName, $file);
}
}
return false;
}
has a boolean $deleteTempFile argument set to true by default. which means it will delete the temporary file after saving and you will not be able to save the uploaded file again in the same request. You can set it to false if needed by doing :
$file_instance->saveAs('...',false)
BUT it won't be a good practice in this case as you are getting 2 copies of the same file. If the file is already saved to its new path then why not deleting it from the tmp folder. Just hold that path in a variable before calling saveAs() and use it when needed like it is done in the answer linked above :
$path = 'uploads/room_img/' . $file_instance->baseName . '.' . $file_instance->extension;
$file_instance->saveAs($path);
$model->images = $path;
Other issues you need to solve are :
foreach ($model->file as $file_instance)
{
$model->save();
$model->images = $path;
}
The $model->save() here have no logic to me. You have a single instance of an object and foreach file instance stored in its attribute $model->file you are saving the hole model again and again. And I understand from the second one ($model->images = $path) that your model have an attribute images to which you can assigning a string value. but you have multiple images here where each of them has its own path and inside the loop you are overriding it each time with the next image path string. If is the case I would probably store the path to folder where I can find all those images later instead :
$model->images = 'uploads/room_img/[a_collection_id_or_wathever_unique]/'
And inside that folder I would host the related images. Or maybe I'll host all paths separated by ; or equivalent by doing this inside the loop :
$model->images .= $path . ';';
In case if images are related models represented by an ActiveRecord class then the answer linked above should fix it.

Exporting Ghost to Wordpress

I've been searching for a possibility to copy my Ghost Blog posts to Wordpress.
So far, I've managed to export all ghost data to a JSON file -- do you know any existing tool to convert it to something Wordpress can import?
If not, and I have to build something myself, would you recommend parsing the JSON to a WXR file or similar, or rather import into Wordpress' DB directly?
Thanks in advance!
K.
I migrated a Ghost blog to Wordpress by reading in the Ghost JSON export, massaging it a little and using wp_insert_post to import the posts.
This code should be placed in your theme's functions.php file - you can export your Ghost posts (GhostData.json) at http://example.com/ghost/debug/.
Note: example below doesn't import all data, but most key fields.
/**
* A function used to programmatically create a post in WordPress.
*
* http://tommcfarlin.com/programmatically-create-a-post-in-wordpress/
*
* #returns post ID if successful
* -1 if the post was never created
* -2 if a post with the same title exists
*/
function create_wp_post ($post_details) {
// Initialize the page ID to -1. This indicates no action has been taken.
$post_id = -1;
$post = get_page_by_title($post_details['title'], 'OBJECT', 'post');
// If the page title doesn't already exist, then insert the post
if (is_null($post)) {
// Set the post ID so that we know the post was created successfully
$post_id = wp_insert_post(
array(
'comment_status' => 'closed',
'ping_status' => 'closed',
'post_author' => $post_details['author'],
'post_content' => $post_details['content'],
'post_date' => $post_details['date'],
'post_date_gmt' => $post_details['date_gmt'],
'post_name' => $post_details['slug'],
'post_status' => $post_details['status'],
'post_title' => $post_details['title'],
'post_type' => 'post',
'tags_input' => $post_details['tags_input']
)
);
// Page title already exists, return error
} else {
$post_id = -2;
}
}
/**
* A function used to filter Ghost blog posts into Wordpress format.
*/
function filter_ghost_posts () {
$posts = json_decode(file_get_contents('GhostData.json'), true);
if ($posts) {
foreach ($posts['data']['posts'] as $post) {
$post_details = array(
'author' => $post['author_id'],
'date' => date('Y-m-d H:i:s', $post['published_at'] / 1000),
'date_gmt' => gmdate('Y-m-d H:i:s', $post['published_at'] / 1000),
'id' => $post['id'],
'content' => $post['html'],
'status' => $post['status'],
'slug' => $post['slug'],
'title' => $post['title']
);
// Status
// Fix discrepancy in naming between Ghost and Wordpress
if ($post_details['status'] === 'published') {
$post_details['status'] = 'publish';
}
// Tags
$post_tags_list = [];
foreach ($posts['data']['posts_tags'] as $post_tags) {
if ($post['id'] === $post_tags['post_id']) {
$post_tags_id = $post_tags['tag_id'];
array_push($post_tags_list, $posts['data']['tags'][$post_tags_id]['name']);
}
}
if (count($post_tags_list) > 0) {
$post_details['tags_input'] = implode(',', $post_tags_list);
}
$post_id = create_wp_post($post_details);
if ($post_id == -1 || $post_id == -2) {
// Error handling here
}
}
}
}
add_filter('after_setup_theme', 'filter_ghost_posts');
My recommendation would be to use Google Refine to import the JSON, and export a CSV, then use WP Ultimate CSV Importer Plugin to import it into your WordPress site. Hope this helps.
The question is quite old, but as of 2017 I still wasn't able to find a solution for Ghost > WP posts migration. What I did is:
Export JSON data, as described here - https://help.ghost.org/hc/en-us/articles/224112927-Import-Export-Data
Change a few JSON fields, like title, markdown... to post_title and post_content etc. (list of WP post fields is here - https://codex.wordpress.org/Class_Reference/WP_Post), and remove a few unneeded ones, like update_at or amp. What I left with was:
ID
post_title
post_name
post_content
post_status
meta_title
meta_description
post_author
post_date
Remove other JSON fields/structure, so there's only "posts": []
Use JSON to CSV converter, like this one - https://konklone.io/json/ and download CSV result file.
Now, when you have a CSV file, install WordPress CSV Importer plugin - https://wordpress.org/plugins/wp-ultimate-csv-importer/ (or similar)
Upload CSV file to the importer, check if fields are selected correctly.
Enjoy the imported posts on your WP dashboard ;)
Notice:
Ghost does not enable image exporting with other data (as of 31/01/2017).
You may wish to change "post_status" from "publish" to "pending", so posts are not published right away, before you edit them properly ;)
In case anyone is looking for this in future:
You could use the ghost-to-wp npm package. This will convert the JSON file you get as an export from Ghost into a WordPress-ready WXR file that can be directly imported into WordPress:
$ npm i -g ghost-to-wp
$ ghost-to-wp yourghostexport.json
As noted by #lomza there is still no way to nicely export images as part of the Ghost file so you will have to migrate images manually.
Disclosure: I am the author of ghost-to-wp.
I tried various importers and the best solution ended up just importing directly from RSS URL like https://myghostblog.com/rss/ with import-xml-feed plugin.
P.S. Keep pagination in mind. Your RSS link might show only first page of posts by default, and so for importing other pages you'll have to manually add /2/ /3/ to the URL and importing each separately. (At least, that's what I needed to do.)