Eu escrevi um plugin que está hospedado no GitHub que permite fazer uploads legais. Um dos recursos que possui é arrastar e soltar de origem cruzada, ou seja, arrastar uma imagem de um site para o uploader. Embora não funcione em alguns sites, por exemplo, página de resultados do Google Images ou anexos do Gmail (obviamente), funciona para a grande maioria dos sites. Hoje vou compartilhar com vocês os truques que fiz para fazê-lo funcionar.
Presumo que você entenda os conceitos básicos OOP
e as funções de arrastar e soltar do HTML5
O JavaScript
var api = !!(win.Blob || win.File || win.FileList || win.FileReader),
canvtest = document.createElement('canvas'),
canv = !!(canvtest.getContext && canvtest.getContext('2d'));
document.body.ondragover = dragOver;
document.body.ondrop = dragDrop;
/**
* Determine whether a value is in an array
* @note Type sensitive
* @param {Array} lookin The array to test
* @param {Mixed} lookfor The thing to lookfor
* @returns {Boolean} True if 'lookfor' is in 'lookin'
*/
function in_array(lookin, lookfor) {
for (var i = 0; i < lookin.length; i++) {
if (lookin[i] === lookfor) {
return true;
}
}
return false;
}
/**
* Drag over event handler
* @param {object(MouseEvent)} e
*/
function dragOver (e) {
var dt = e.dataTransfer;
if (!in_array(dt.types, 'Files') && in_array(dt.types, 'text/uri-list')) {
// The thing we are hovering with IS NOT a file, return.
return;
};
e.stopPropagation();
e.preventDefault();
dt.dropEffect = 'copy';
}
/**
* Drop event handler
* @param {object(MouseEvent)} e
*/
function dragDrop (e) {
// Prevent an accidental drop outside the drop zone
e.stopPropagation();
e.preventDefault();
if ($(e.target).closest('#mydropzonewrapper').length) {
// Only accept drops inside the drop zone
var dt = e.dataTransfer,
files = dt.files;
if (!files.length && canv) {
// We may have a uri-list
var tdp = filesrc = dt.getData('url');
if (!filesrc) {
filesrc = dt.getData('text/plain');
if (!filesrc) {
filesrc = dt.getData('text/uri-list');
if (!filesrc) {
// We have tried all that we can to get this url but we can't. Abort mission
return;
}
}
}
$.ajax({
url: '/processing.php',
type: 'post',
dataType: 'json',
data: {filesrc: filesrc, uploaddir: 'destinationfolder'}
}).done(function (e) {
if (e.result === 'OK') {
// The file has been successfully 'uploaded'
console.log(e.data);
if (e.data.mimetype.match('image/*')) {
var img = new Image();
img.onload = function () {
// Special image processing
};
img.onerror = function () {
// Special image processing
};
// Add '?cachekill=unixtime' to prevent the browser from caching
img.src = e.data.src + '?cachekill=' + (new Date().getTime());
} else {
// Normal processing
}
} else {
// There was an error
}
}).fail(function () {
// There was an error
});
return;
}
}
// Normal file processing
}
O PHP (processing.php)
cExternalUpload::processExternalUpload();
class cExternalUpload {
static $settings;
/**
* Retrieve a file from another server, save it and pretend that it was an upload from our system
*/
static function processExternalUpload () {
$path = filter_input(INPUT_POST, 'filesrc');
self::$settings = new stdClass();
self::$settings->uploaddir = filter_input(INPUT_POST, 'uploaddir');
self::setUploadDir();
try {
$pathbits = explode('/', $path);
$filename = substr(preg_replace('/[^a-z0-9_.]/', '_', strtolower(end($pathbits))), 0, 100);
$destination = self::$settings->uploaddir . time() . '_' . $filename;
$relpath = substr($destination, strlen(filter_input(INPUT_SERVER, 'DOCUMENT_ROOT')));
self::save($destination, $path);
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mimetype = finfo_file($finfo, $destination);
$output = array(
'src' => $relpath,
'name' => $filename,
'mimetype' => $mimetype
);
if (preg_match("/image/.*/", $mimetype)) {
// The 'uploaded' file is an image
$size = getimagesize($destination);
$output['width'] = $output['croppedWidth'] = $output['resizedWidth'] = $size[0];
$output['height'] = $output['croppedHeight'] = $output['resizedHeight'] = $size[1];
}
self::ajaxExit('OK', $output);
} catch (Exception $ex) {
self::ajaxExit('Fail', "Unable to get external file: {$ex->getMessage()}");
}
}
/**
* Send a JSON-encoded response from an Ajax call and exit
* @param $result string Message to return to the browser
* @param $data mixed Any additional data to return
* @param $status int Value of HTTP status to be sent to the browser
*/
private static function ajaxExit($result, $data = null, $status = 200) {
header('Content-Type:text/json; charset=utf-8');
header("HTTP/1.0 $status");
$response = array('result' => $result);
if (!empty($data)) {
$response['data'] = $data;
}
print json_encode($response);
exit;
}
/**
* Save an external file
* @param string $destination The destination of the upload
* @param string $src The path to the external file
* @return int The number of bytes written, or false on failure
* @throws Exception
*/
static function save($destination, $src) {
$ans = @file_put_contents($destination, file_get_contents($src));
if ($ans === false) {
throw new Exception("Could not write data to {$destination}");
}
if (!(fileperms($destination) & 0020)) {
if (!chmod($destination, 0777)) {
throw new Exception('Failed to change permissions on ' . $destination);
}
}
return $ans;
}
/**
* Set the destination path for the uploaded file
* @return string The destination path
*/
private static function setUploadDir() {
$uploaddir = self::$settings->uploaddir;
if(!preg_match("//$/", $uploaddir)) {
// The upload dir requires a '/' at the end
$uploaddir = self::$settings->uploaddir = "{$uploaddir}/";
}
if(substr($uploaddir, 0, 1) === '/') {
$uploaddir = self::$settings->uploaddir = substr($uploaddir, 0);
}
self::$settings->uploaddir = filter_input(INPUT_SERVER, 'DOCUMENT_ROOT') . "/$uploaddir";
}
}
Aproveite e comente se você não entender nada do código