I'm using TinyMCE 5 with PHP 7.
Currently:
1. images_upload_handler (working)
Following the TinyMCE guide on Drag-in uploading images, and my own PHP upload AJAX handler, I got an image to upload successfully to my uploads directory:
This correctly uploads the file and keeps the correct name, using AJAX.
It uses a function for images_upload_handler, calling my AJAX handler.
2. file_picker_callback (incomplete)
Following the TinyMCE demo on uploading files, I got these two toolbar buttons (image, media) to show an upload button in their dialogs:
This works for image, not media.
It uses a function for file_picker_callback, uploading its own way.
3. The problem
I can't get the file_picker_callback from 2. to upload from media and I want it to use my own AJAX upload handler anyway, which I can't.
Using the image tool to upload, it will save the file after clicking "Save" in the dialog. But, when used in the media tool, it will not upload or insert anything at all.
It seems that this JavaScript demo provided by TinyMCE has a heavy interaction with the TinyMCE API itself. It has a system of caching and blobs to find the file that TinyMCE uploaded on its own. So pure AJAX-JS knowledge isn't sufficient to tell me how to tell TinyMCE to use my own AJAX upload PHP file. I'd rather just override TinyMCE's upload handler in file_picker_callback so I can use my own PHP upload script to be compatible with the rest of my app.
Goal:
I need a function for file_picker_callback (the file upload button) to use my own AJAX upload handler and preserve the name just as images_upload_handler succeeds in doing.
I am not worried about filename and mimetype validation; I plan to have PHP sanitize and filter later on.
This Question addresses another file uploader and the problem of TinyMCE 4 solutions not always working with TinyMCE 5.
This Question is about image description, and only for images; I want to upload any filetype.
I do not want any dependencies, not even jQuery. Vanilla JS only.
Current Code:
| upload.php :
$temp_file = $_FILES['file']['tmp_name'];
$file_path_dest = 'uploads/'.$_FILES['file']['name'];
move_uploaded_file($temp_file, $file_path_dest);
$json_file_is_here = json_encode(array('filepath' => $file_path_dest));
echo $json_file_is_here;
| tinyinit.js :
tinymce.init({
selector: 'textarea',
plugins: [ 'image media imagetools', ],
automatic_uploads: true,
images_reuse_filename: true,
images_upload_url: 'upload.php',
// From #1. Successful AJAX Upload
images_upload_handler: function(fileHere, success, fail) {
var ajax = new XMLHttpRequest();
ajax.withCredentials = false;
ajax.open('post', 'upload.php');
ajax.upload.onprogress = function (e) {
progress(e.loaded / e.total * 100);
};
ajax.onload = function() {
if (ajax.status == 200) {
if ( (!JSON.parse(ajax.responseText))
|| (typeof JSON.parse(ajax.responseText).filepath != 'string') ) {
fail('Invalid: <code>'+ajax.responseText+'</code>');
return;
}
success(JSON.parse(ajax.responseText).filepath);
} else {
fail('Upload error: <code>'+ajax.status+'</code>');
return;
}
};
var fileInfo = new FormData();
fileInfo.append('file', fileHere.blob(), fileHere.filename());
ajax.send(fileInfo);
},
file_browser_callback_types: 'file image media',
file_picker_types: 'file image media',
// From #2. Neither uploads from "media" nor uses my upload handler
file_picker_callback: function(cb, value, meta) {
var input = document.createElement('input');
input.setAttribute('type', 'file');
input.onchange = function() {
var file = this.files[0];
var reader = new FileReader();
reader.onload = function () {
var blobCache = tinymce.activeEditor.editorUpload.blobCache;
var base64 = reader.result.split(',')[1];
var blobInfo = blobCache.create(file.name, file, base64);
blobCache.add(blobInfo);
cb(blobInfo.blobUri(), { title: file.name });
};
reader.readAsDataURL(file);
};
input.click();
}
});
Editing #Aulia's Answer :
file_picker_callback: function (cb, value, meta) {
var input = document.createElement('input');
input.setAttribute('type', 'file');
input.onchange = function () {
var file = this.files[0];
var reader = new FileReader();
// FormData
var fd = new FormData();
var files = file;
fd.append('filetype',meta.filetype);
fd.append("file",files);
var filename = "";
// AJAX
var xhr, formData;
xhr = new XMLHttpRequest();
xhr.withCredentials = false;
xhr.open('POST', '/your-endpoint');
xhr.onload = function() {
var json;
if (xhr.status != 200) {
alert('HTTP Error: ' + xhr.status);
return;
}
json = JSON.parse(xhr.responseText);
if (!json || typeof json.location != 'string') {
alert('Invalid JSON: ' + xhr.responseText);
return;
}
filename = json.location;
reader.onload = function(e) {
cb(filename);
};
reader.readAsDataURL(file);
};
xhr.send(fd);
return
};
input.click();
}
In the configuration you've provided, #2 doesn't have any logic to upload the data to your server. The code from Tiny's documentation you've copied is just for demo purposes and won't allow you to upload files to Tiny's servers.
You will need to setup the file_picker_callback callback to send data similar to images_upload_handler. On your server, you will need to send the URI and title in the response so the following line will be fulfilled:
cb(blobInfo.blobUri(), { title: file.name });
Hope it will helps mate, make your file_picker_callback looks like below codes
file_picker_callback: function (cb, value, meta) {
var input = document.createElement('input');
input.setAttribute('type', 'file');
input.onchange = function () {
var file = this.files[0];
var reader = new FileReader();
// FormData
var fd = new FormData();
var files = file;
fd.append('filetype',meta.filetype);
fd.append("file",files);
var filename = "";
// AJAX
var xhr, formData;
xhr = new XMLHttpRequest();
xhr.withCredentials = false;
xhr.open('POST', '/your-endpoint');
xhr.onload = function() {
var json;
if (xhr.status != 200) {
failure('HTTP Error: ' + xhr.status);
return;
}
json = JSON.parse(xhr.responseText);
if (!json || typeof json.location != 'string') {
failure('Invalid JSON: ' + xhr.responseText);
return;
}
success(json.location);
filename = json.location;
};
xhr.send(fd);
reader.onload = function(e) {
cb(filename);
};
reader.readAsDataURL(file);
return
};
input.click();
},
Related
Having an issue with uploading images on Tiny. I want to upload the images to folder /images/owner/ I don't want a blob, but rather to upload full files.
I can upload to file_upload.php no problem from test.html. Containing a text input and a file input only. file_upload.php looks like this ...
<?php
/***************************************************
* Only these origins are allowed to upload images *
***************************************************/
$accepted_origins = array("http://localhost", "http://192.168.1.1", "https://example.com/");
/*********************************************
* Change this line to set the upload folder *
*********************************************/
$owner_id=$_POST["owner"];
//$owner_id='15601a2cc3d5b2';
$imageFolder = "images/". $owner_id . "/";
// Don't attempt to process the upload on an OPTIONS request
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
header("Access-Control-Allow-Methods: POST, OPTIONS");
return;
}
reset($_FILES);
$temp = current($_FILES);
if (is_uploaded_file($temp['tmp_name'])){
// Sanitize input
if (preg_match("/([^\w\s\d\-_~,;:\[\]\(\).])|([\.]{2,})/", $temp['name'])) {
header("HTTP/1.1 400 Invalid file name.");
return;
}
// Verify extension
if (!in_array(strtolower(pathinfo($temp['name'], PATHINFO_EXTENSION)), array("gif", "jpg", "png"))) {
header("HTTP/1.1 400 Invalid extension.");
return;
}
// Accept upload if there was no origin, or if it is an accepted origin
$filetowrite = $imageFolder . $temp['name'];
move_uploaded_file($temp['tmp_name'], $filetowrite);
// Determine the base URL
$protocol = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on' ? "https://" : "http://";
$baseurl = $protocol . $_SERVER["HTTP_HOST"] . rtrim(dirname($_SERVER['REQUEST_URI']), "/") . "/";
// Respond to the successful upload with JSON.
// Use a location key to specify the path to the saved image resource.
// { location : '/your/uploaded/image/file'}
echo json_encode(array('location' => $baseurl . $filetowrite));
} else {
// Notify editor that the upload failed
header("HTTP/1.1 500 Server Error");
}
?>
This Tiny JS code is on my editor.php page. I don't want a blob that can't be linked to. I want to send an email newsletter and only proper files/images on the server will render...
<script>
tinymce.init({
selector: '#mytextarea',
images_upload_handler: images_upload_handler,
plugins: 'image code',
toolbar: 'undo redo | link image',
/* enable title field in the Image dialog*/
image_title: true,
/* enable automatic uploads of images represented by blob or data URIs*/
automatic_uploads: true,
/*
URL of our upload handler (for more details check: https://www.tiny.cloud/docs/configure/file-image-upload/#images_upload_url)
images_upload_url: './js/tinymce/postAcceptor.php',
here we add custom filepicker only to Image dialog
*/
file_picker_types: 'image',
/* and here's our custom image picker*/
file_picker_callback: function (cb, value, meta) {
var input = document.createElement('input');
input.setAttribute('type', 'file');
input.setAttribute('accept', 'image/*');
/*
Note: In modern browsers input[type=\"file\"] is functional without
even adding it to the DOM, but that might not be the case in some older
or quirky browsers like IE, so you might want to add it to the DOM
just in case, and visually hide it. And do not forget do remove it
once you do not need it anymore.
*/
input.onchange = function () {
var file = this.files[0];
var reader = new FileReader();
reader.onload = function () {
/*
Note: Now we need to register the blob in TinyMCEs image blob
registry. In the next release this part hopefully won't be
necessary, as we are looking to handle it internally.
*/
var id = 'blobid' + (new Date()).getTime();
var blobCache = tinymce.activeEditor.editorUpload.blobCache;
var base64 = reader.result.split(',')[1];
var blobInfo = blobCache.create(id, file, base64);
blobCache.add(blobInfo);
/* call the callback and populate the Title field with the file name */
cb(blobInfo.blobUri(), { title: file.name });
};
reader.readAsDataURL(file);
};
input.click();
},
content_style: 'body { font-family:Helvetica,Arial,sans-serif; font-size:14px }'
});
function images_upload_handler (blobInfo, success, failure, progress) {
var xhr, formData;
xhr = new XMLHttpRequest();
xhr.withCredentials = false;
xhr.open('POST','https://example.com/myfolder/file-upload.php');
xhr.upload.onprogress = function (e) {
progress(e.loaded / e.total * 100);
};
xhr.onload = function() {
var json;
if (xhr.status === 403) {
failure('HTTP Error: ' + xhr.status, { remove: true });
return;
}
if (xhr.status < 200 || xhr.status >= 300) {
failure('HTTP Error: ' + xhr.status);
return;
}
json = JSON.parse(xhr.responseText);
if (!json || typeof json.location != 'string') {
failure('Invalid JSON: ' + xhr.responseText);
return;
}
success(json.location);
};
xhr.onerror = function () {
failure('Image upload failed due to a XHR Transport error. Code: ' + xhr.status);
};
formData = new FormData();
formData.append('owner','" . $owner_id . "');
formData.append('file', blobInfo.blob(), blobInfo.filename());
xhr.send(formData);
};
When i do this from chrome web dev ...
xhr = new XMLHttpRequest();
xhr.withCredentials = false;
xhr.open('POST','https://example.com/myfolder/file-upload.php');
formData = new FormData();
formData.append('owner','ddddddddd');
formData.append('file', '/home/me/Desktop/image/mail.png');
xhr.send(formData);
I get array(0) {}
I can't send both values, owner and file. I've stacked them in the correct order.
Also have to click upload on the Tiny editor image popup, when i use General it gives me a blob.
No luck. Sorry if this post is kinda verbose. Thought you'd need all the code to help...
By default tinymce image has no browse button where you can click and see a dialog box to choose an image. In my code am trying to add image picker button to tinymce but am finding it difficult to combine it with the images_upload_handler. And lastly how do i use the success callback to update images_upload_base_path.
tinymce.init({
...
images_upload_handler: function (blobInfo, success, failure) {
var xhr, formData;
xhr = new XMLHttpRequest();
xhr.withCredentials = false;
xhr.open('POST', "postAcceptor.php");
xhr.onload = function() {
var json;
if (xhr.status != 200) {
failure("HTTP Error: " + xhr.status);
return;
}
json = JSON.parse(xhr.responseText);
if (!json || typeof json.location != "string") {
failure("Invalid JSON: " + xhr.responseText);
return;
}
success(json.location);
};
formData = new FormData();
formData.append('file', blobInfo.blob(), blobInfo.filename());
xhr.send(formData);
}
});
I don't really understand why, but for me images_upload_handler not works as well... =(
Use file_picker_callback instead, like in this example that I found:
https://codepen.io/nirajmchauhan/pen/EjQLpV
I have an image created with a JavaScript Blob which I need to upload to a PHP script.
My JavaScript upload function...
function upload(blobOrFile) {
var xhr = new XMLHttpRequest();
xhr.open('POST', 'http://requestb.in/17m14c51', true);
xhr.onload = function(e) {
//
};
// Listen to the upload progress.
//var progressBar = document.querySelector('progress');
xhr.upload.onprogress = function(e) {
if (e.lengthComputable) {
console.log((e.loaded / e.total) * 100);
//progressBar.textContent = progressBar.value; // Fallback for unsupported browsers.
}
};
xhr.send(blobOrFile);
}
This URL http://requestb.in/17m14c51?inspect shows the data that this code is posting.
My Image is coming in as an image. I am not sure how to access this image in my PHP script though as I do not see any form or file name, maybe I am missing it?
Previously my PHP had the image come in as Base64 so this PHP below did the upload...
function base64_to_jpeg($base64_string, $output_file) {
//$output_file_new= $output_file.'-'.md5(time().uniqid()).'.jpg';
$output_file_new= $output_file;
$ifp = fopen($output_file_new, "wb");
$base64_string2 = urldecode($base64_string);
$data = explode(',', $base64_string2);
$decoded = base64_decode($data[1]);
fwrite($ifp, $decoded);
fclose($ifp);
echo json_encode(array('img_url' => $output_file_new, 'headers' => parseRequestHeaders()));
//return $output_file_new;
}
Now that I am not getting it as Base64, how can I save it in my PHP?
I'm looking for some way to upload video via XHR, and video convert, my script in XHR looks like.
var files= $("#camera"+id).prop('files');
var file = files[0];
var cList= files.length;
$("#camera"+id).val('');
$("#textarea"+id).val('');
var fd = new FormData();
fd.append("file", file);
fd.append("name", name);
fd.append("desc", desc);
fd.append('id', id);
var xhr = new XMLHttpRequest();
xhr.open("POST", "addUcChallenge.php", true);
xhr.upload.onprogress = function(e)
{
};
xhr.onload = function()
{
if(this.status == 200)
{
cList = 1;
//alert(xhr.responseText);
};
};
if(cList < 1)
{
}
else
{
xhr.send(fd);
}
When I tried to upload video is happen nothink, and when I wanted return some value of file nothing too, but photos are ok, and second think is that I don't know how to handle with video in PHP ( Upload, convert to flv ) Thank you!
For uploading you can use PlUploader code example (that is used for large file uploading and make sure you have edited the max file uploading size in php.ini file if you are using php in backend) and for conversion you have to use the FFMPEG
What techniques are used to load a file (ASCII or Binary) into a variable (var file = "text";) in JavaScript?
You want to use the new HTML5 File API and XMLHttpRequest 2.
You can listen to files being either selected via a file input or drag & dropped to the browser. Let's talk about the input[type="file"] way.
<input type="file">
Let's listen for files being selected.
var input; // let input be our file input
input.onchange = function (e) {
var files = input.files || [];
var file = files[0];
if (file) {
uploadFile(file);
}
};
What you need to create a real multipart file upload request is a FormData object. This object is a representation of the body of your HTTP POST request.
var uploadFile = function (file) {
var data = new FormData();
data.append('filename', file);
// create a HTTP POST request
var xhr = new XMLHttpRequest();
xhr.open('POST', './script.php', true);
xhr.send(data);
xhr.onloadend = function () {
// code to be executed when the upload finishes
};
};
You can also monitor the upload progress.
xhr.upload.onprogress = function (e) {
var percentage = 100 * e.loaded / e.total;
};
Ask if you need any clarification.
If you want to use the new HTML5 way this is how I did it... keep in mind that I made a method called File() and this is not a true HTML5 method its a wrapper to it... this might be changed in the future so beware (maybe rename it).
HTML:
<html>
<body>
<input type="file" id="files" name="file"/>
<button onclick="load()">Load File</button><br /><br />
<div id="content"></div>
<script>
function load() {
var fileObj = document.getElementById("files");
var fp = new File(fileObj);
fp.read(callback);
}
function callback(text) {
var content = document.getElementById("content");
content.innerHTML = text;
}
</script>
</body>
</html>
JavaScript:
function File(name) {
this.name = document.getElementById(name) ? document.getElementById(name).files : name.files ? name.files : name;
}
// Reads the file from the browser
File.prototype.read = function(callback) {
var files = this.name;
if (!files.length) {
alert('Please select a file!?');
return;
}
var file = files[0];
var reader = new FileReader();
reader.onloadend = function(evt) {
if (evt.target.readyState == FileReader.DONE) { // DONE == 2
callback(evt.target.result);
}
};
var data = file.slice(0, file.size);
reader.readAsBinaryString(data);
}
Have the JavaScript being generated inside a PHP or Rails (or whatever you use server-side) and include the file.
<?php
$my_string = file_get_contents('/path/to/file.txt');
?>
<script>
var my_js_file_string = "<?php echo $my_string; ?>";
...
document.write(my_js_file_string);
</script>