I have this php code that is supposed to backup an image /optimise the image and the reupload the image to shopify
It works but for a few images before it timesout because there are a lot of images and each image several processes.
There are more than 500 images. Any way I can process all these images without the script timesout?
Here is the code
<?php
//ini_set("display_errors", 1);
//error_reporting(E_ALL);
ini_set('memory_limit', '-1');
require_once("inc/functions.php");
require_once("lib/Tinify/Exception.php");
require_once("lib/Tinify/ResultMeta.php");
require_once("lib/Tinify/Result.php");
require_once("lib/Tinify/Source.php");
require_once("lib/Tinify/Client.php");
require_once("lib/Tinify.php");
\Tinify\setKey("xxxxxxxxx");
$requests = $_GET;
//$hmac = $_GET['hmac'];
$serializeArray = serialize($requests);
$requests = array_diff_key($requests, array('hmac' => ''));
ksort($requests);
$token = "xxxxxx";
$shop = "xxxxx"; //no 'myshopify.com' or 'https'
$storeURL = "https://" . $shop . ".myshopify.com";
$path = realpath("images");
if ( ! is_dir($path)) {
mkdir('images', 0777);
}
$i = 1;
do {
if ($i == 1) {
$date = '2040-01-01T12:00:00-00:00';
}
$array = array('limit' => '250', 'order' => 'created_at desc', 'created_at_max' => $date);
$products = shopify_call($token, $shop, '/admin/api/2020-01/products.json', $array, 'GET');
$products = json_decode($products['response'], JSON_PRETTY_PRINT);
$i++;
foreach ($products['products'] as $product) {
$date = $product['created_at'];
foreach ($product['images'] as $image) {
$image_id = $image['id'];
$image_tag = $image['alt'];
$image_position = $image['position'];
/* Process 1: download and save image (Backup) */
$path = realpath('images/' . $product['id']);
if ( ! is_dir($path)) {
mkdir('images/' . $product['id'], 0777);
}
$fileurl = $image['src'];
$fileName = basename($image['src']);
$names = explode('?v=', $fileName);
file_put_contents('images/' . $product['id'] . '/' . $names[0], file_get_contents($image['src']));
/* End Process 1 */
/* Process 2: Optimise and save optimised Image */
$source = \Tinify\fromUrl($fileurl);
$path = realpath('images/' . $product['id'] .'/optimized');
if ( ! is_dir($path)) {
mkdir('images/' . $product['id'] .'/optimized', 0777);
}
$source->toFile("images/" . $product['id'] . "/optimized/". $names[0]);
/* End Process 2 */
$image = array(
"image" => array(
"id" => $image_id,
)
);
/* Process 3: Delete image from shopify */
$delete_image = shopify_call($token, $shop, "/admin/products/" . $product['id'] . "/images/".$image_id .".json", $image, 'DELETE');
$deleted = $delete_image['response'];
/* End Process 3 */
/* Process 4: Upload Optimised image to shopify */
$imgurl = "http://xxxx/vendor/images/" . $product['id'] . "/optimized/". $names[0];
$upload_image = array(
"image" => array(
"position"=>$image_position,
"alt"=> $image_tag,
"src"=> $imgurl
)
);
$upimage = shopify_call($token, $shop, "/admin/products/" . $product['id']. "/images.json", $upload_image, 'POST');
$uploaded = $upimage['response'];
/* End Process 4 */
}
}
} while (count($products['products']) == 250);
Any advice is highly appreciated. Thanks
Related
When I update the database, it uploads a single image. How do I upload multiple?
$id = $this->request->getPost('id');
$model = new UrunModel();
$file = $this->request->getFile('resim');
$resim_eski = $model->find($id);
if($file->isValid() && !$file->hasMoved()){
$eski_resim = $resim_eski['resim'];
if(file_exists("dosyalar/uploads".$eski_resim)){
unlink("dosyalar/uploads".$eski_resim);
}
$imagename = $file->getRandomName();
$file->move("dosyalar/uploads", $imagename);
}else{
$imagename = $resim_eski['resim'];
}
if ($this->request->getFileMultiple('images')) {
foreach($this->request->getFileMultiple('images') as $res)
{
$res->move(WRITEPATH . 'dosyalar/uploads');
$data=[
'baslik' => $this->request->getPost('baslik'),
'slug' => mb_url_title($this->request->getPost('baslik'), '-', TRUE),
'kisa_aciklama' => $this->request->getPost('kisa_aciklama'),
'kategori' => $this->request->getPost('kategori'),
'query_kategori' => $this->request->getPost('query_kategori'),
'aciklama' => $this->request->getPost('aciklama'),
'fiyat' => $this->request->getPost('fiyat'),
'indirimli_fiyat' => $this->request->getPost('indirimli_fiyat'),
'resim' => $imagename,
'resimler' => $res->getClientName(),
'type' => $res->getClientMimeType()
];
$model -> update($id,$data);
}
}
return redirect()->to(base_url('yonetim/urunler'));
}
Controller code above, I've been struggling for 2 days, I couldn't manage it somehow.
When I run the code, it just adds 1 image to each product. I want to add more than one image to 1 product for the gallery part. Any suggestions for this code or a different solution?
function add()
{
$length = count($_FILES['image']['name']);
$filename = $_FILES['image']['name'];
$tempname = $_FILES['image']['tmp_name'];
$allimage = array();
foreach($filename as $key =>$value)
{
move_uploaded_file($tempname[$key],'media/uploads/mobile_product/'.$filename[$key]);
$allimage[] = $filename[$key];
}
if(!empty($allimage))
{
$allimage = json_encode($allimage);
}
else
{
$allimage = '';
}
$data['image'] = $allimage;
$this->db->insert('table',$data);
}
CI4 Controller:
if($this->request->getFileMultiple('image_files')) {
$files = $this->request->getFileMultiple('image_files');
foreach ($files as $file) {
if ($file->isValid() && ! $file->hasMoved())
{
$newNames = $file->getRandomName();
$imageFiles = array(
'filename' => $newNames
);
$modelName->insert($imageFiles );
$file->move('uploads/', $newNames);
}
}
}
HTML
<input type="file" name="image_files[]">
This is the shortest way to do that
It is not possible to transfer data from one controller to another. There is such a controller for filling mp3 files via Dropzone.JS:
public function upload(Request $request)
{
if (!$request->has('file')) {
return response()->json(['message' => 'Missing file'], 422);
}
$file = $request->file('file');
$extension = !is_null($file->extension()) ? $file->extension() : 'mp3';
$fileName = !is_null($file->getClientOriginalName()) ? rtrim($file->getClientOriginalName(), '.') : 'Unknown - Unknown.mp3';
$tracksPath = 'public/tracks/';
$globalPath = storage_path('app/public/tracks/');
$globalTrackPath = $globalPath . $fileName;
$file->move(storage_path('app/public/tracks'), $fileName);
$fileHash = sha1_file($globalTrackPath);
rename($globalTrackPath, $globalPath . $fileHash . '.' . $extension);
$track = GetId3::fromDiskAndPath('storage', 'app/public/tracks/' . $fileHash . '.' . $extension);
$t = $track->extractInfo();
$title = !empty($t['tags']['id3v2']['title']['0']) ? $t['tags']['id3v2']['title']['0'] : 'Unknown';
$artist = !empty($t['tags']['id3v2']['artist']['0']) ? $t['tags']['id3v2']['artist']['0'] : 'Unknown';
$band = !empty($t['tags']['id3v2']['band']['0']) ? $t['tags']['id3v2']['band']['0'] : '';
$album = !empty($t['tags']['id3v2']['album']['0']) ? $t['tags']['id3v2']['album']['0'] : '';
$year = !empty($t['tags']['id3v2']['year']['0']) ? $t['tags']['id3v2']['year']['0'] : '';
$genre = !empty($t['tags']['id3v2']['genre']['0']) ? $t['tags']['id3v2']['genre']['0'] : '';
$url = Storage::url($tracksPath . $fileHash . '.mp3');
if(!empty($track->getArtwork(true))) {
$tmpCoverFile = $track->getArtwork(true)->getPathname();
$coverPath = 'public/tracks/covers/';
$cover64Path = 'cover.jpg';
Storage::disk('local')->put($coverPath . '/' . $fileHash . '/' . $cover64Path, File::get($tmpCoverFile));
$cover = Storage::url($coverPath . $fileHash . '/' . $cover64Path);
} else {
$cover = '/vendor/songs-crud/images/none.png';
}
DB::table('songs_tracks')->updateOrInsert(
['hash' => $fileHash],
[
'release_id' => $request->id,
'image' => $cover,
'name' => $title,
'artist' => $artist,
'band' => $band,
'album' => $album,
'year' => $year,
'genre' => $genre,
'url' => $url,
'hash' => $fileHash,
'sortable' => '',
'slug' => $fileHash
]
);
$getTrackId = DB::table('songs_tracks')
->where('hash', $fileHash)
->first();
$id = !empty($getTrackId->id) ? $getTrackId->id : 1;
return $id;
}
The function works fine, media files are uploaded to the server and records are added to the database table. I need to pass the id to another function that generates a JSON file:
public function getTrackListJson(Request $request): \Illuminate\Http\JsonResponse
{
dd($this->upload());
$tracks = DB::table('songs_tracks')->where('id', $id)->first();
return response()->json([$tracks]);
}
I'm trying to print this function via dd(), but it gives the following error:
ArgumentCountError
Too few arguments to function SequelONE\SongsCRUD\app\Http\Controllers\Admin\TrackCrudController::upload(), 0 passed in /home/site.com/packages/sequelone/songs-crud/src/app/Http/Controllers/Admin/TrackCrudController.php on line 229 and exactly 1 expected
I can't figure out how to pass an instance of $request and do I need to pass it at all? Can anyone help with this?
When you call a function that requires parameter, or uses injection like the Laravel Request, then you need to pass it in when you call the function manually. Since you're already injecting Request $request on your getTrackListJson call, you can just pass that along.
dd($this->upload($request));
That might help
public function getTrackListJson(Request $request): \Illuminate\Http\JsonResponse
{
$id = $this->upload($request);
$tracks = DB::table('songs_tracks')->where('id', $id)->first();
return response()->json([$tracks]);
}
I'm trying to create a new folder within the upload folder so that a user can upload file to there own folder.
Can I do this using PHP or do I need to a column "LONGBLOB" in MYSQL?
I've read that it's not good practice to store images in you database
<?php
header('Content-Type: application/json');
$succeeded = [];
$failed =[];
$uploaded = [];
$allowed = ['png', 'gif', 'jpg'];
if(!empty($_FILES["file"])) {
foreach ($_FILES['file']['name'] as $key => $name) {
if ($_FILES['file']['error'][$key] === 0) {
$temp = $_FILES['file']['tmp_name'][$key];
$ext = explode('.', $name);
$ext = strtolower(end($ext));
$file = md5_file($temp) . time() . '.' . $ext;
if (in_array($ext, $allowed) === true && move_uploaded_file($temp, "uploads/{$file}") === true) {
$succeeded[] = array(
'name' => $name,
'file' => $file
);
}else{
$failed[] = array(
'name' => $name);
}
}
}
}
if (!empty($_POST['ajax'])) {
echo json_encode(array(
'succeeded' => $succeeded,
'failed' => $failed ));
}
?>
Assuming you have the user's username or id in a session variable then that could be used as the basis for the new folder into which he/she would upload files.
Obiously that same username,id would have to be used when they wish to download the file. By storing a hash and the filepath you can generate links that do not reveal filename, folder path, owner etc as the db could check the ash and return the file and path when needed.
The following is an untested example of generating the user's own folder and using that in the upload process - hope it gives you some ideas / guidance.
<?php
$succeeded = [];
$failed =[];
$uploaded = [];
$allowed = ['png', 'gif', 'jpg'];
/*
generate a suitable name for the new folder,
remove characters which might be troublesome
*/
$userdir = str_replace(
array("'",'"','-'),
array('','','_'),
$_SESSION['username']
);
/*
new path into which the files are saved
It might be better to have the files
stored outside of the document root.
*/
$savepath = 'uploads/' . $userdir;
/* create the folder if it does not exist */
if( !file_exists( $savepath ) ) {
mkdir( $savepath );
chown( $savepath, $username );
chmod( $savepath, 0644 );
}
if( !empty( $_FILES["file"] ) ) {
foreach( $_FILES['file']['name'] as $key => $name ) {
if( $_FILES['file']['error'][$key] === 0 ) {
$temp = $_FILES['file']['tmp_name'][$key];
/*
is there anything to be gained by hashing the filename?
the hash would be the same for filenames with the same
name anyway.
If the file is large, calculating the hash of the file could
take some time...
*/
$ext = explode('.', $name);
$ext = strtolower( end( $ext ) );
$file = md5_file( $temp ) . time() . '.' . $ext;
/* generate a random hash to use in downloads */
$hash=uniqid( md5( date(DATE_COOKIE) ) );
/* here probably - store reference in db? Assign permissions based upon owner etc */
$sql='insert into `table` (`filename`,`username`,`uid`,`datetime`,`hash`) values (?,?,?,?,?);';
/* bind params and execute - not shown */
if ( in_array( $ext, $allowed ) === true && move_uploaded_file( $temp, "{$savepath}/{$file}") === true ) {
$succeeded[] = array( 'name' => $name, 'file' => $file );
}else{
$failed[] = array( 'name' => $name );
}
}
}
}
if (!empty($_POST['ajax'])) {
header('Content-Type: application/json');
echo json_encode(array(
'succeeded' => $succeeded,
'failed' => $failed ));
} else {
header( 'HTTP/1.1 404 Not Found', true, 404 );
}
?>
I am currently doing an internship and I tried to make an activity module to show playlist, from video given by a filemanager. I succeed to send the video to the database but when I want to edit my module, it doesn't show any videos in the filemanager.
I read the moodle documentation about file API and I decided to use the following code (Load existing files into draft area)
:
if (empty($entry->id)) {
$entry = new stdClass;
$entry->id = null;
}
$draftitemid = file_get_submitted_draft_itemid('attachments');
file_prepare_draft_area($draftitemid, $context->id, 'mod_glossary','attachment', $entry->id,array('subdirs' => 0, 'maxbytes' => $maxbytes, 'maxfiles' => 50));
$entry->attachments = $draftitemid;
$mform->set_data($entry);
So I put the following lines in my mod_form.php :
$filemanager_options = array();
$filemanager_options['accepted_types'] = '*';
$filemanager_options['maxbytes'] = 0;
$filemanager_options['maxfiles'] = -1;
$filemanager_options['mainfile'] = true;
$mform->addElement('filemanager', 'files', get_string('selectfiles'), null, $filemanager_options);
if (empty($entry->id)) {
$entry = new stdClass;
$entry->id = null;
}
$draftitemid = file_get_submitted_draft_itemid('mymanager');
file_prepare_draft_area($draftitemid, $this->context->id, 'mod_playlist', 'content', 0,
array('subdirs'=>true));
$entry->attachments = $draftitemid;
$mform->set_data($entry);
The problem is that the file manager is still empty, and the line "$mform->set_data($entry); " makes the page to crash(blank).
Here is a template for uploading files.
In local/myplugin/upload.php
require_once(dirname(dirname(dirname(__FILE__))) . '/config.php');
require_once(dirname(__FILE__) . '/upload_form.php');
require_login();
$context = context_system::instance();
require_capability('local/myplugin:upload', $context);
$pageurl = new moodle_url('/local/myplugin/upload.php');
$heading = get_string('myupload', 'local_myplugin');
$PAGE->set_context($context);
$PAGE->set_heading(format_string($heading));
$PAGE->set_title(format_string($heading));
$PAGE->set_url('/local/myplugin/upload.php');
echo $OUTPUT->header();
echo $OUTPUT->heading($heading);
$fileoptions = array(
'maxbytes' => 0,
'maxfiles' => '1',
'subdirs' => 0,
'context' => context_system::instance()
);
$data = new stdClass();
$data = file_prepare_standard_filemanager($data, 'myfiles',
$fileoptions, context_system::instance(), 'local_myplugin', 'myfiles', 0); // 0 is the item id.
$mform = new upload_form(
null,
array(
'fileoptions' => $fileoptions,
)
);
if ($formdata = $mform->get_data()) {
// Save the file.
$data = file_postupdate_standard_filemanager($data, 'myfiles',
$fileoptions, context_system::instance(), 'local_myplugin', 'myfiles', 0);
} else {
// Display the form.
$mform->set_data($data);
$mform->display();
}
echo $OUTPUT->footer();
Then in local/myplugin/upload_form.php
defined('MOODLE_INTERNAL') || die;
require_once($CFG->libdir . '/formslib.php');
class upload_form extends moodleform {
public function definition() {
$mform =& $this->_form;
$fileoptions = $this->_customdata['fileoptions'];
$mform->addElement('filemanager', 'myfiles_filemanager',
get_string('myfiles', 'local_myplugin'), null, $fileoptions);
$this->add_action_buttons(false, get_string('save', 'local_myplugin'));
}
}
You will also need this in /local/myplugin/lib.php
function local_myplugin_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload, array $options = array()) {
if ($context->contextlevel != CONTEXT_SYSTEM) {
send_file_not_found();
}
$fs = get_file_storage();
$file = $fs->get_file($context->id, 'local_myplugin', $filearea, $args[0], '/', $args[1]);
send_stored_file($file);
}
Problem
I'm working on an integration with Magento which first removes all images from a product and then add new ones. The problem is that when I add them the 'thumbnail', 'small_image' and 'image' only gets set on the default store and not the individual stores.
Code
public function setProductImages($entityId, $images, $websiteIds, $removeFirst = true){
$product = Mage::getModel('catalog/product')->load($entityId);
if($removeFirst){
//First I need to reset image selection before I can remove all images
$values = array(
'image' => 'no_selection',
'small_image' => 'no_selection',
'thumbnail' => 'no_selection'
);
//Go through all sites and stores and set the image selection values
foreach($websiteIds as $websiteId) {
$website = Mage::getModel('core/website')->load($websiteId);
foreach ($website->getStoreIds() as $storeId) {
Mage::getSingleton('catalog/product_action')->updateAttributes(array($product->getId()), $values, $storeId);
}
}
//Set the selection values on admin store
Mage::getSingleton('catalog/product_action')->updateAttributes(array($product->getId()), $values, 0);
//Remove all images on product
$mediaGalleryAttribute = Mage::getModel('catalog/resource_eav_attribute')->loadByCode($product->getEntityTypeId(), 'media_gallery');
$gallery = $product->getMediaGalleryImages();
foreach ($gallery as $galleryImage) {
$imageFile = $galleryImage->getFile();
$mediaGalleryAttribute->getBackend()->removeImage($product, $imageFile);
}
$product->save();
}
foreach($images as $image) {
file_put_contents($path . DS . $image->filename, $image->content);
$type = in_array($image->name, array('image', 'small_image', 'thumbnail')) ? $image->name : null;
$product->addImageToMediaGallery($path . DS . $image->filename, $type, true, false);
}
$product->save();
}
Is there some way to tell addImageToMediaGallery to set on an array of stores? Or am I missing something?
Solved it by replacing
foreach($images as $image) {
file_put_contents($path . DS . $image->filename, $image->content);
$type = in_array($image->name, array('image', 'small_image', 'thumbnail')) ? $image->name : null;
$product->addImageToMediaGallery($path . DS . $image->filename, $type, true, false);
}
$product->save();
with this:
$imageTypes = array();
//Sets images on default store for product
foreach($images as $image){
file_put_contents($path . DS . $image->filename, $image->content);
$type = in_array($image->name, array('image', 'small_image', 'thumbnail')) ? $image->name : null;
$product->addImageToMediaGallery($path . DS . $image->filename, $type, true, false);
//Store image, small_image and thumbnail for later use
$imageTypes['image'] = $product->getImage();
$imageTypes['small_image'] = $product->getSmallImage();
$imageTypes['thumbnail'] = $product->getThumbnail();
}
$product->save();
//Go through all stores and set image, small_image and thumbnail
foreach($websiteIds as $websiteId) {
$website = Mage::getModel('core/website')->load($websiteId);
foreach($website->getStoreIds() as $storeId) {
Mage::app()->setCurrentStore($storeId);
Mage::getSingleton('catalog/product_action')->updateAttributes(array($product->getId()), $imageTypes, $storeId);
}
}
$product->save();