So I am trying to transfer/copy a large file from a remote server to my server in separate parts or chunks. I tried the script provided here:
https://stackoverflow.com/a/4000569/7559794
I made some changes and gave a form to the script and used AJAX to communicate with PHP script as follows:
The index.html contains a form with POST method and a submit button that calls the following function OnClick:
<script>
function stratdown() {
var partsizevalue = $('#psize').val();
var dfilename = $('#dfile').val();
var sfilename = $('#sfile').val();
$.ajax({
type: "POST",
url: 'trigger.php',
data:{dfile: dfilename, sfile: sfilename, psize: partsizevalue}, //{value: a, cID: cID}
success:function(result) {
alert(result);
}
});
}</script>
the file trigger.php contains the following script:
<?php
require 'partdown.php';
$infile = $_POST["dfile"];
$outfile = $_POST["sfile"];
$partsize = $_POST["psize"];
echo $mesg = DownInParts::copyfile_chunked($infile, $outfile, $partsize);
?>
and the required partdown.php contains:
<?php
/**
* Copy remote file over HTTP one small chunk at a time.
*
* #param $infile The full URL to the remote file
* #param $outfile The path where to save the file
*/
class DownInParts
{
public function copyfile_chunked($infile, $outfile, $partsize)
{
$chunksize = $partsize * 1024; // 10 Megs
/**
* parse_url breaks a part a URL into it's parts, i.e. host, path,
* query string, etc.
*/
$parts = parse_url($infile);
$i_handle = fsockopen($parts['host'], 80, $errstr, $errcode, 5);
$o_handle = fopen($outfile, 'wb');
if ($i_handle == false || $o_handle == false) {
return false;
}
if (!empty($parts['query'])) {
$parts['path'] .= '?' . $parts['query'];
}
/**
* Send the request to the server for the file
*/
$request = "GET {$parts['path']} HTTP/1.1\r\n";
$request .= "Host: {$parts['host']}\r\n";
$request .= "User-Agent: Mozilla/5.0\r\n";
$request .= "Keep-Alive: 115\r\n";
$request .= "Connection: keep-alive\r\n\r\n";
fwrite($i_handle, $request);
/**
* Now read the headers from the remote server. We'll need
* to get the content length.
*/
$headers = array();
while(!feof($i_handle)) {
$line = fgets($i_handle);
if ($line == "\r\n") break;
$headers[] = $line;
}
/**
* Look for the Content-Length header, and get the size
* of the remote file.
*/
$length = 0;
foreach($headers as $header) {
if (stripos($header, 'Content-Length:') === 0) {
$length = (int)str_replace('Content-Length: ', '', $header);
break;
}
}
/**
* Start reading in the remote file, and writing it to the
* local file one chunk at a time.
*/
$cnt = 0;
while(!feof($i_handle)) {
$buf = '';
$buf = fread($i_handle, $chunksize);
$bytes = fwrite($o_handle, $buf);
if ($bytes == false) {
return false;
}
$cnt += $bytes;
/**
* We're done reading when we've reached the content length
*/
if ($cnt >= $length) break;
}
fclose($i_handle);
fclose($o_handle);
return $cnt;
}
}
?>
I didn't manage to make it function. I have however tried to add the action "trigger.php" to the form in order to call PHP directly yet The file I downloaded was (0 Kb) in size. Any ideas.
I think I have just missed adding this two line in the < head > section due to stress.
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
This did the trick for me. Now I need a progress bar and a success alert.
Related
I'm using DropzoneJS to upload my images. So what I do is to take the base64URL generated by dropzoneJS, and then try to upload as follows:
$( document ).ready(function() {
var endpoint= $("#endpoint").val();
var unit = {
name: '',
description: '',
image: '',
base64Image: '',
themes: []
}
$("#create-unit-btn").on("click", function() {
unit.name = $("#create-name").val();
unit.description = $("#create-description").val();
unit.base64Image = $('#imageDropzone')[0].dropzone.files[0].dataURL;
var data = {
'_token': $('meta[name=csrf-token]').attr('content'),
'unit': unit
}
console.log(data);
$.ajax({
type: "POST",
url: endpoint,
data: data,
success: function(result){
console.log(result);
}
});
});
function validate() {
}
});
Then to upload the Image I use the following code:
public function create( Request $request ) {
$data = [];
$code = 200;
try {
$unit = new Unit();
$unit->name = request()->input('unit.name');
$unit->description = request()->input('unit.description');
$url = ImageHandler::StoreBase64ToFile($request->input('unit.base64Image'));
$unit->image = $url;
$unit->save();
$data['unit'] = $unit;
} catch ( \Illuminate\Database\QueryException $e ) {
// There was an error
$code = Response::HTTP_UNPROCESSABLE_ENTITY;
$data = [];
$data['error'] = ErrorResponse::create($code, $e->getMessage());
} catch( ModelNotFoundException $e ) {
return response()->json(['error' => 'invalid operation'], 406);
}
return response()->json($data, $code);
}
The ImageHandler class does the following:
<?php
namespace App\Libraries;
use Storage;
class ImageHandler {
/**
* Store a base64 image into the file system this data has to be
* sended without any header info like:
* data:image/png;base64
* So the info will look something like iVBORw0....hEUgAAAcQ==
* #param string $base64Data information
* #param string $filename the filename if not defined then it generates
* a random name
* #param string $disk disk location, check Storage documentation of
* laravel, by default is stored on the public folder
* so you'll have to run
* php artisan storage:link
* to make the symbolink links
* #return string url location of the file
*/
public static function StoreBase64ToFile($base64Data,
$filename = null,
$disk = 'public')
{
if (strlen($base64Data) < 10) {
return null;
}
$image = base64_decode($base64Data);
if ($filename == null) {
$filename = str_random(16);
$filename .= '_'.time();
$filename .= '.png';
}
$path = 'images/'.$filename;
$result = Storage::disk($disk)->put($path, $image, 'public');
if ($result) {
$url = Storage::disk($disk)->url($path);
return $url;
}
return null;
}
}
But when I upload the image, even that the process ends correctly, when I try to open the file from my file browser (finder on MacOs), I can't see the uploaded image. I mean the file it’s there but I cant see the content of the image
I don't know why is not been uploaded correctly.
It was an error of format when I stored the Image. In order to upload the file without any problem I had to do the following before send the request: unit.base64Image = unit.base64Image.replace("data:image/png;base64,", "");
I have a reporting website that I use DataTables Server Side Processing on. Everything works great except that I need to be able to export the whole data set and not just the part that is showing on the screen. I have reports that have 10,000+ rows and 65+ columns so showing the whole report on the page is out of the question (would take more than 5 minutes and then time out). I've gotten really close to an answer, I think, but need help getting the rest of the way. Here's what I've got:
I'm collecting the data that I need sending it to a file that uses PHPExcel libraries to export an Excel file.
When I navigate to the file (ExportAllToExcel.php) it works fine, but when I use a button to send the data to the file there is no download. Here's what I've got going right now:
$.fn.dataTable.ext.buttons.export =
{
className: 'buttons-alert',
id: 'ExportButton',
text: "Export All Test III",
action: function (e, dt, node, config)
{
var SearchData = dt.rows({ filter: 'applied' }).data();
var OrderData = dt.order();
var NumRow = SearchData.length;
var SearchData2 = [];
for (j = 0; j < NumRow; j++)
{
var NewSearchData = SearchData[j];
for (i = 0; i < NewSearchData.length; i++)
{
NewSearchData[i] = NewSearchData[i].replace("<div class='Scrollable'>", "");
NewSearchData[i] = NewSearchData[i].replace("</div>", "");
}
SearchData2.push([NewSearchData]);
}
for (i = 0; i < SearchData2.length; i++)
{
for (j = 0; j < SearchData2[i].length; j++ )
{
SearchData2[i][j] = SearchData2[i][j].join('::');
}
}
SearchData2 = SearchData2.join("%%");
//var SendPageData = new XMLHttpRequest();
//SendPageData.open("POST", "./ExportAllToExcel.php", true);
//SendPageData.send('{NumRow=' + NumRow + '},{SearchData=' + SearchData2 + '}');
$.post('./ExportAllToExcel.php',{SearchData: SearchData2,NumRow: NumRow});
window.location.href = './ExportAllToExcel.php';
}
};
This doesn't work. The $.POST sends the data and gets a response, but does not export the file.
The Window.location goes to the file and exports to Excel but doesn't have the data from $_POST so the file only has headers.
And the SendPageData does the same as the $.POST sends the data and gets a response, but doesn't create the file.
And here's the ExportAllToExcel.php:
<?php
require $_SERVER['DOCUMENT_ROOT'].'/dev/Location/Helper/PageName.php'; //Pulls the Page name and Table name and returns the $SQLTableName, $TableName, $Title, $Page and $HeadingDesc
include $_SERVER['DOCUMENT_ROOT'].'/dev/Location/DBConn.php'; //DB connection info
$headings = array(); //Create the empty array for use later and so that it won't throw an error if not assinged later
$hsql = "select Headings from TableHeadings where TableName = '$TableName' order by Id"; //Get all the column headers from the TableHeadings table in SQL
$getHeadings = $conn->query($hsql);
$rHeadings = $getHeadings->fetchALL(PDO::FETCH_ASSOC);
$CountHeadings = count($rHeadings); //Count how many columns that there will be
$tsqlHeadings = '';
$ColumnHeader = array();
for ($row = 0; $row < $CountHeadings; $row++)
{
$headings[$row] = $rHeadings[$row]["Headings"]; //fill the array of column headings for use in creating the DataTable
}
print_r($headings);
// Error reporting
error_reporting(E_ALL);
ini_set('display_errors', TRUE);
ini_set('display_startup_errors', TRUE);
if (PHP_SAPI == 'cli')
die('This example should only be run from a Web Browser');
// Add some data
$ColumnArray = array('A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','AA','AB','AC','AD','AE','AF','AG','AH','AI','AJ','AK','AL','AM','AN','AO','AP','AQ','AR','AS','AT','AU','AV','AW','AX','AY','AZ');
//$HeadingArray = array('Year','Quater','Country','Sales');
$HeadingArray = $headings;
$primaryKey = 'id';
$table = $SQLTableName;
$request = $_POST;
$dataArray = array();
$dataArraystr = explode('%%',$_POST['SearchData']);
foreach($dataArraystr as $ArrayStr)
{
$dataArray[] = explode('::',$ArrayStr);
}
// Include PHPExcel
require_once dirname(__FILE__) . './Classes/PHPExcel.php';
// Create new PHPExcel object
$objPHPExcel = new PHPExcel();
// Set document properties
$objPHPExcel->getProperties()->setCreator("Michael McNair")
->setLastModifiedBy("Michael McNair")
->setTitle($TableName)
->setSubject($TableName)
->setDescription("Report for " .$TableName. " using PHPExcel, generated using PHP classes.")
->setKeywords("office PHPExcel php " . $TableName)
->setCategory("Report Export File");
$objPHPExcel->getActiveSheet()->fromArray($HeadingArray, NULL, 'A1');
$objPHPExcel->getActiveSheet()->fromArray($dataArray, NULL, 'A2');
$CountOfArray = count($HeadingArray);
// Set title row bold
$objPHPExcel->getActiveSheet()->getStyle('A1:' .$ColumnArray[$CountOfArray-1]. '1')->getFont()->setBold(true);
// Set autofilter
// Always include the complete filter range!
// Excel does support setting only the caption
// row, but that's not a best practise...
$objPHPExcel->getActiveSheet()->setAutoFilter($objPHPExcel->getActiveSheet()->calculateWorksheetDimension());
// Rename worksheet
$objPHPExcel->getActiveSheet()->setTitle('SimpleTest');
// Add a second sheet, but infront of the existing sheet
//$myWorkSheet = new PHPExcel_Worksheet($objPHPExcel,'New Worksheet');
//$objPHPExcel->addSheet($myWorkSheet,0);
// Set active sheet index to the first sheet, so Excel opens this as the first sheet
$objPHPExcel->setActiveSheetIndex(0);
// Redirect output to a client’s web browser (Excel2007)
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Content-Disposition: attachment;filename="ExportAllToExcelTest.xlsx"');
header('Cache-Control: max-age=0');
// If you're serving to IE 9, then the following may be needed
header('Cache-Control: max-age=1');
// If you're serving to IE over SSL, then the following may be needed
header ('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); // Date in the past
header ('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); // always modified
header ('Cache-Control: cache, must-revalidate'); // HTTP/1.1
header ('Pragma: public'); // HTTP/1.0
$objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel2007');
///$objWriter = new PHPExcel_Writer_Excel2007($objPHPExcel);
ob_clean();
$objWriter->save('php://output');
?>
I have fixed the problem. This is the button now:
$.fn.dataTable.ext.buttons.export =
{
className: 'buttons-alert',
id: 'ExportButton',
text: "Export All To Excel",
action: function (e, dt, node, config)
{
window.location.href = './ServerSide.php?ExportToExcel=Yes';
}
};
I use just the one $_GET and send that to my ServerSide.php file, the same file that gets the data for the browser, to begin with. There I now check for that and use my KeepPost.php file to keep the filtering and sorting that the user has placed on the report:
<?php
if( isset($_POST['draw']))
{
include 'DBConn.php';
//echo "Here";
//print_r($_POST);
$KeepPost = $_POST;
$KeepPost['length'] = -1;
$PostKept = serialize($KeepPost);
$TSQL = "UPDATE PostKept set Value = '" .$PostKept. "'";
$sth = $conn->prepare($TSQL);
//print_r($sth);
$sth->execute();
}
?>
Then in ServerSide.php I check for the $_GET['ExportToExcel']:
if (isset($_GET['ExportToExcel']) && $_GET['ExportToExcel'] == 'Yes')
{
$GetSQL = "Select Value from PostKept";
$KeepResult = $conn->query($GetSQL);
$KeepResults = $KeepResult->fetchALL(PDO::FETCH_ASSOC);
//print_r($KeepResults);
error_log(date("Y/m/d h:i:sa")." KeepResults: " .$KeepResults[0]['Value']. "\n",3,"C:\Temp\LogPHP.txt");
//findSerializeError($_COOKIE['KeepPost']);
//print_r($_COOKIE);
$request = unserialize($KeepResults[0]['Value']);
//echo "<br>Request: "; print_r($request);
$DataReturn = json_encode(FilterSort::complex($request,$sqlConnect,$table,$primaryKey,$ColumnHeader,1));
//echo "DataReturn:<br>"; print_r($DataReturn);
require './ExportAllToExcel.php';
}
This then sends the correct data to the ExportAllToExcel.php file and exports the data the users wants.
I'm new and learning web development and all. I only know how to embed my videos in the website and the source can be easily obtained by any noobs and they can embed it too. but in many website the video src is encoded with a redirector link, for example: https://redirector.googlevideo.com/videoplayback?requiressl=yes&id=0c5d32687bb8e7fd&itag=18&source=webdrive&ttl=transient&app=explorer&ip=2604:a880:0:1010::dc7:d001&ipbits=32&expire=1481329545&sparams=requiressl%2Cid%2Citag%2Csource%2Cttl%2Cip%2Cipbits%2Cexpire&signature=8094D8DEF3C98784DC5561980B5725379B61A804.4C63CCB219699C4A2C02FB2606425E50243F8D36&key=ck2&mm=31&mn=sn-ab5l6ne6&ms=au&mt=1481314943&mv=m&nh=IgpwcjA0LmxnYTA3KgkxMjcuMC4wLjE&pl=48
It expires after some time, in this case, a day. I've learnt that this is a signed url.
So, i would like to know how to create a signed url like this. Please dont give any plugin names coz i'm not a paid user or anything i'm using blogger only. i just wanna learn how to code it in javascript.
In short, I want to make lets say, source of my embeded youtube video to be a signed url which expires after an hour and the source should keep changing when the site is refreshed.
Edit: After doing this, I noticed you were using YouTube video embeds, not actual video files. But nevermind, I'll just leave this here...
Since you did not mention NodeJS anywhere, I'm guessing you're expecting to do this in JS in the browser. But for that to happen in the browser, you would need the have the real video URL sent to the client, and expose to the public your URL signing functions. Which defeats the purpose of having signed URLs.
I gave it a try using PHP, and it's not very complicated. Here is the process:
When a user requests your page, you create a temporary URL for him. This URL contains a signature, which contains the filepath to the video and an expiration date. It leads to a page which will translate the signature, and serve the file if everything is correct.
I see you don't want to use libraries, but I used "home made" libraries, which will help keep things well organized. Here is the file structure I used:
/
├── libraries/
│ ├── VideoStream.php
│ └── VideoSignature.php
├── index.php
├── video.mp4
└── getVideo.php
libraries/VideoSignature.php
Note that you need to change the settings at the top to suit your needs
<?php
/*
* This class allows you to:
* - Encrypt filepaths and expiration dates into signatures
* - Decrypt signatures into filepaths and expiration dates
*
*
* Note: String encryption functions were found here:
* http://stackoverflow.com/a/1289114/1913729
*/
class VideoSignature
{
// Time before a URL expires, in seconds
private $expires = 10;
// Key used to sign your URLs
private $encryption_key = 'soMeStr0ngP455W0rD!!';
// Public URL used to serve the content
private $proxy_url = '/getVideo.php';
// Encrypts a string
private function encryptStr($str){
$iv = mcrypt_create_iv(
mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC),
MCRYPT_DEV_URANDOM
);
$encrypted = base64_encode(
$iv .
mcrypt_encrypt(
MCRYPT_RIJNDAEL_128,
hash('sha256', $this->encryption_key, true),
$str,
MCRYPT_MODE_CBC,
$iv
)
);
return $encrypted;
}
// Decrypts a String
private function decryptStr($str){
$data = base64_decode($str);
$iv = substr($data, 0, mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC));
$decrypted = rtrim(
mcrypt_decrypt(
MCRYPT_RIJNDAEL_128,
hash('sha256', $this->encryption_key, true),
substr($data, mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC)),
MCRYPT_MODE_CBC,
$iv
),
"\0"
);
return $decrypted;
}
// Returns a temporary URL
public function getSignedURL($filepath){
$data = json_encode(
array(
"filepath" => $filepath,
"expires" => time() + $this->expires
)
);
$signature = $this->encryptStr($data);
return $this->proxy_url . "?s=" . urlencode($signature);
}
// Returns a filepath from a signature if it did not expire
public function getFilepath($signature){
$data = json_decode( $this->decryptStr($signature), true);
if($data !== null && $data['expires'] > time() && file_exists($data['filepath'])){
return $data['filepath'];
}
return false;
}
}
libraries/VideoStream.php
<?php
/*
* This class was found here:
* http://stackoverflow.com/a/39897793/1913729
*
* It allows you to stream video without giving the real file URL
*/
class VideoStream
{
private $path = "";
private $stream = "";
private $buffer = 102400;
private $start = -1;
private $end = -1;
private $size = 0;
function __construct($filePath)
{
$this->path = $filePath;
}
/**
* Open stream
*/
private function open()
{
if (!($this->stream = fopen($this->path, 'rb'))) {
die('Could not open stream for reading');
}
}
/**
* Set proper header to serve the video content
*/
private function setHeader()
{
ob_get_clean();
header("Content-Type: video/mp4");
header("Cache-Control: max-age=2592000, public");
header("Expires: ".gmdate('D, d M Y H:i:s', time()+2592000) . ' GMT');
header("Last-Modified: ".gmdate('D, d M Y H:i:s', #filemtime($this->path)) . ' GMT' );
$this->start = 0;
$this->size = filesize($this->path);
$this->end = $this->size - 1;
header("Accept-Ranges: 0-".$this->end);
if (isset($_SERVER['HTTP_RANGE'])) {
$c_start = $this->start;
$c_end = $this->end;
list(, $range) = explode('=', $_SERVER['HTTP_RANGE'], 2);
if (strpos($range, ',') !== false) {
header('HTTP/1.1 416 Requested Range Not Satisfiable');
header("Content-Range: bytes $this->start-$this->end/$this->size");
exit;
}
if ($range == '-') {
$c_start = $this->size - substr($range, 1);
}else{
$range = explode('-', $range);
$c_start = $range[0];
$c_end = (isset($range[1]) && is_numeric($range[1])) ? $range[1] : $c_end;
}
$c_end = ($c_end > $this->end) ? $this->end : $c_end;
if ($c_start > $c_end || $c_start > $this->size - 1 || $c_end >= $this->size) {
header('HTTP/1.1 416 Requested Range Not Satisfiable');
header("Content-Range: bytes $this->start-$this->end/$this->size");
exit;
}
$this->start = $c_start;
$this->end = $c_end;
$length = $this->end - $this->start + 1;
fseek($this->stream, $this->start);
header('HTTP/1.1 206 Partial Content');
header("Content-Length: ".$length);
header("Content-Range: bytes $this->start-$this->end/".$this->size);
}
else
{
header("Content-Length: ".$this->size);
}
}
/**
* close curretly opened stream
*/
private function end()
{
fclose($this->stream);
exit;
}
/**
* perform the streaming of calculated range
*/
private function stream()
{
$i = $this->start;
set_time_limit(0);
while(!feof($this->stream) && $i <= $this->end) {
$bytesToRead = $this->buffer;
if(($i+$bytesToRead) > $this->end) {
$bytesToRead = $this->end - $i + 1;
}
$data = fread($this->stream, $bytesToRead);
echo $data;
flush();
$i += $bytesToRead;
}
}
/**
* Start streaming video content
*/
function start()
{
$this->open();
$this->setHeader();
$this->stream();
$this->end();
}
}
index.php
<?php
// Load the signature helper functions
include "libraries/VideoSignature.php";
$vs = new VideoSignature();
?><!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Check out my video!</title>
</head>
<body>
<!-- /!\ Here, you need to insert a path to your video,
relative to the getVideo.php file, not an actual URL! -->
<video src="<?=$vs->getSignedURL("server/path/to/video.mp4");?>"></video>
</body>
</html>
getVideo.php
<?php
// Load the signature helper functions
include "libraries/VideoSignature.php";
$vs = new VideoSignature();
// Load the video streaming functions
include "libraries/VideoStream.php";
if(isset($_REQUEST['s']) && $filepath = $vs->getFilepath($_REQUEST['s'])){
$stream = new VideoStream($filepath);
$stream->start();
} else {
header("HTTP/1.0 403 Forbidden");
echo "This URL has expired.";
}
I am using this upload widget in my web application.
I am using the FormDataUploader and I am able to upload files to a server directory quite well. However, I wanted to send extra parameters as well to the php file handling the upload. This is what I attempted:
var uploadPanel = Ext.create('Ext.ux.upload.Panel', {
uploader : 'Ext.ux.upload.uploader.FormDataUploader',
uploaderOptions : {
url : 'uploadGallery.php'
},
synchronous : true,
uploadParams : {
ID_Person : ID_Person,
ID_CI : ID_CI
}
});
As you can see, I used the uploadParams, however, my PHP couldn't seem to receive it. In my php file, I have:
$ID_Person = $_GET['ID_Person'];
$ID_CI = $_GET['ID_CI'];
However, my PHP seems to be unable to get these params.
What I did next was to use the default ExtJS Uploader as such:
var uploadPanel = Ext.create('Ext.ux.upload.Panel', {
uploaderOptions : {
url : 'uploadExtJS.php'
},
synchronous : true,
uploadParams : {
ID_Person : ID_Person,
ID_CI : ID_CI
}
});
At first, I used the old PHP file which was able to get the extra params I sent. However, it seems that I needed to use a different PHP file for the ExtJS uploader.
This is what my PHP file looks like:
<?php
/**
* Example processing of raw PUT/POST uploaded files.
* File metadata may be sent through appropriate HTTP headers:
* - file name - the 'X-File-Name' proprietary header
* - file size - the standard 'Content-Length' header or the 'X-File-Size' proprietary header
* - file type - the standard 'Content-Type' header or the 'X-File-Type' proprietary header
*
* Raw data are read from the standard input.
* The response should be a JSON encoded string with these items:
* - success (boolean) - if the upload has been successful
* - message (string) - optional message, useful in case of error
*/
require __DIR__ . '_common.php';
$config = require __DIR__ . '_config.php';
error_reporting(-1);
ini_set('display_errors', 'On');
/*
* You should check these values for XSS or SQL injection.
*/
if (!isset($_SERVER['HTTP_X_FILE_NAME'])) {
_error('Unknown file name');
}
$fileName = $_SERVER['HTTP_X_FILE_NAME'];
if (isset($_SERVER['HTTP_X_FILENAME_ENCODER']) && 'base64' == $_SERVER['HTTP_X_FILENAME_ENCODER']) {
$fileName = base64_decode($fileName);
}
$fileName = htmlspecialchars($fileName);
$mimeType = htmlspecialchars($_SERVER['HTTP_X_FILE_TYPE']);
$size = intval($_SERVER['HTTP_X_FILE_SIZE']);
$inputStream = fopen('php://input', 'r');
// $outputFilename = $config['upload_dir'] . '/' . $fileName;
$outputFilename = 'gallery' . '/' . $fileName;
$realSize = 0;
$data = '';
if ($inputStream) {
if (! $config['fake']) {
$outputStream = fopen($outputFilename, 'w');
if (! $outputStream) {
_error('Error creating local file');
}
}
while (! feof($inputStream)) {
$bytesWritten = 0;
$data = fread($inputStream, 1024);
if (! $config['fake']) {
$bytesWritten = fwrite($outputStream, $data);
} else {
$bytesWritten = strlen($data);
}
if (false === $bytesWritten) {
_error('Error writing data to file');
}
$realSize += $bytesWritten;
}
if (! $config['fake']) {
fclose($outputStream);
}
} else {
_error('Error reading input');
}
if ($realSize != $size) {
_error('The actual size differs from the declared size in the headers');
}
_log(sprintf("[raw] Uploaded %s, %s, %d byte(s)", $fileName, $mimeType, $realSize));
_response();
However, I am getting an Internal Server 500 Error - Meaning that there was something probably wrong with my php file.
I mainly have two questions:
How do I make the uploadParams work with the FormDataUploader?
How do I write a PHP uploader for an ExtJS Data Uploader?
Got it to work.
The uploadExtJS.php file should look like:
<?php
/**
* Example processing of raw PUT/POST uploaded files.
* File metadata may be sent through appropriate HTTP headers:
* - file name - the 'X-File-Name' proprietary header
* - file size - the standard 'Content-Length' header or the 'X-File-Size' proprietary header
* - file type - the standard 'Content-Type' header or the 'X-File-Type' proprietary header
*
* Raw data are read from the standard input.
* The response should be a JSON encoded string with these items:
* - success (boolean) - if the upload has been successful
* - message (string) - optional message, useful in case of error
*/
// require __DIR__ . '_common.php';
// $config = require __DIR__ . '_config.php';
require_once '_common.php';
$config = require_once '_config.php';
error_reporting(-1);
ini_set('display_errors', 'On');
/*
* You should check these values for XSS or SQL injection.
*/
if (!isset($_SERVER['HTTP_X_FILE_NAME'])) {
_error('Unknown file name');
}
$fileName = $_SERVER['HTTP_X_FILE_NAME'];
if (isset($_SERVER['HTTP_X_FILENAME_ENCODER']) && 'base64' == $_SERVER['HTTP_X_FILENAME_ENCODER']) {
$fileName = base64_decode($fileName);
}
$fileName = htmlspecialchars($fileName);
$mimeType = htmlspecialchars($_SERVER['HTTP_X_FILE_TYPE']);
$size = intval($_SERVER['HTTP_X_FILE_SIZE']);
$inputStream = fopen('php://input', 'r');
$outputFilename = $config['upload_dir'] . '/' . $fileName;
// $outputFilename = 'gallery' . '/' . $fileName;
$realSize = 0;
$data = '';
if ($inputStream) {
if (! $config['fake']) {
$outputStream = fopen($outputFilename, 'w');
if (! $outputStream) {
_error('Error creating local file');
}
}
while (! feof($inputStream)) {
$bytesWritten = 0;
$data = fread($inputStream, 1024);
if (! $config['fake']) {
$bytesWritten = fwrite($outputStream, $data);
} else {
$bytesWritten = strlen($data);
}
if (false === $bytesWritten) {
_error('Error writing data to file');
}
$realSize += $bytesWritten;
}
if (! $config['fake']) {
fclose($outputStream);
}
} else {
_error('Error reading input');
}
if ($realSize != $size) {
_error('The actual size differs from the declared size in the headers');
}
_log(sprintf("[raw] Uploaded %s, %s, %d byte(s)", $fileName, $mimeType, $realSize));
_response(true, "okay");
_common.php looks like:
<?php
function _log($value){
error_log(print_r($value, true));
}
function _response($success = true, $message = 'OK'){
$response = array(
'success' => $success,
'message' => $message
);
echo json_encode($response);
exit();
}
function _error($message){
return _response(false, $message);
}
_config.php should look like:
<?php
return array(
'upload_dir' => 'gallery',
'fake' => false
);
?>
and now I'm working on using a unique name using uniqid() and microtime(), as well as saving the images to a subdirectory (or any folder under your main upload/gallery folder) using the uploadParams() property.
EDIT 1: RENAMING THE UPLOADED FILE
just change this line:
$fileName = htmlspecialchars($fileName);
to:
$fileName = uniqid() . '_' . microtime();
EDIT 3: TO GET THE CUSTOM SUB DIRECTORY FROM YOUR ADDITIONAL PARAMS
First, make sure than when you create your Upload Dialog from your ExtJS web app, you do this:
var uploadPanel = Ext.create('Ext.ux.upload.Panel', {
uploaderOptions : {
url : 'uploadExtJS.php'
},
synchronous : true,
uploadParams : {
ID_1 : ID_1,
ID_2 : ID_2 // you can put waaay more if you want
}
});
and in your uploadExtJS.php, do this (between the part where you define your new file name and the part where you check for input stream)
$fileName = uniqid() . '_' . microtime();
$mimeType = htmlspecialchars($_SERVER['HTTP_X_FILE_TYPE']);
$size = intval($_SERVER['HTTP_X_FILE_SIZE']);
$ID_1 = $_GET['ID_1'];
$ID_2 = $_GET['ID_2'];
$newFilePath = $config['upload_dir'] . '/' . $ID_1 . '/' . $ID_2;
if (!file_exists($newFilePath)) {
mkdir($newFilePath, 0777, true);
}
$inputStream = fopen('php://input', 'r');
$outputFilename = $newFilePath . '/' . $fileName;
$realSize = 0;
$data = '';
As you can see, I defined a $newFilePath variable, checked if it was existing before making it, then uploaded to that directory.
Hope this helps anyone who encounters the issue in the future.
I'm using a reCaptcha class (the one that's included in the Tank Auth authentication library for Codeigniter) and wanted to know if it's possible to change the background and text color of the image reCaptcha returns?
Here is the actual reCaptcha Helper PHP code included with Tank Auth:
<?php
/*
* This is a PHP library that handles calling reCAPTCHA.
* - Documentation and latest version
* http://recaptcha.net/plugins/php/
* - Get a reCAPTCHA API Key
* http://recaptcha.net/api/getkey
* - Discussion group
* http://groups.google.com/group/recaptcha
*
* Copyright (c) 2007 reCAPTCHA -- http://recaptcha.net
* AUTHORS:
* Mike Crawford
* Ben Maurer
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/**
* The reCAPTCHA server URL's
*/
define("RECAPTCHA_API_SERVER", "http://api.recaptcha.net");
define("RECAPTCHA_API_SECURE_SERVER", "https://api-secure.recaptcha.net");
define("RECAPTCHA_VERIFY_SERVER", "api-verify.recaptcha.net");
/**
* Encodes the given data into a query string format
* #param $data - array of string elements to be encoded
* #return string - encoded request
*/
function _recaptcha_qsencode ($data) {
$req = "";
foreach ( $data as $key => $value )
$req .= $key . '=' . urlencode( stripslashes($value) ) . '&';
// Cut the last '&'
$req=substr($req,0,strlen($req)-1);
return $req;
}
/**
* Submits an HTTP POST to a reCAPTCHA server
* #param string $host
* #param string $path
* #param array $data
* #param int port
* #return array response
*/
function _recaptcha_http_post($host, $path, $data, $port = 80) {
$req = _recaptcha_qsencode ($data);
$http_request = "POST $path HTTP/1.0\r\n";
$http_request .= "Host: $host\r\n";
$http_request .= "Content-Type: application/x-www-form-urlencoded;\r\n";
$http_request .= "Content-Length: " . strlen($req) . "\r\n";
$http_request .= "User-Agent: reCAPTCHA/PHP\r\n";
$http_request .= "\r\n";
$http_request .= $req;
$response = '';
if( false == ( $fs = #fsockopen($host, $port, $errno, $errstr, 10) ) ) {
die ('Could not open socket');
}
fwrite($fs, $http_request);
while ( !feof($fs) )
$response .= fgets($fs, 1160); // One TCP-IP packet
fclose($fs);
$response = explode("\r\n\r\n", $response, 2);
return $response;
}
/**
* Gets the challenge HTML (javascript and non-javascript version).
* This is called from the browser, and the resulting reCAPTCHA HTML widget
* is embedded within the HTML form it was called from.
* #param string $pubkey A public key for reCAPTCHA
* #param string $error The error given by reCAPTCHA (optional, default is null)
* #param boolean $use_ssl Should the request be made over ssl? (optional, default is false)
* #return string - The HTML to be embedded in the user's form.
*/
function recaptcha_get_html ($pubkey, $error = null, $use_ssl = false)
{
if ($pubkey == null || $pubkey == '') {
die ("To use reCAPTCHA you must get an API key from <a href='http://recaptcha.net/api/getkey'>http://recaptcha.net/api/getkey</a>");
}
if ($use_ssl) {
$server = RECAPTCHA_API_SECURE_SERVER;
} else {
$server = RECAPTCHA_API_SERVER;
}
$errorpart = "";
if ($error) {
$errorpart = "&error=" . $error;
}
return '<script type="text/javascript" src="'. $server . '/challenge?k=' . $pubkey . $errorpart . '"></script>
<noscript>
<iframe src="'. $server . '/noscript?k=' . $pubkey . $errorpart . '" height="300" width="500" frameborder="0"></iframe><br/>
<textarea name="recaptcha_challenge_field" rows="3" cols="40"></textarea>
<input type="hidden" name="recaptcha_response_field" value="manual_challenge"/>
</noscript>';
}
/**
* A ReCaptchaResponse is returned from recaptcha_check_answer()
*/
class ReCaptchaResponse {
var $is_valid;
var $error;
}
/**
* Calls an HTTP POST function to verify if the user's guess was correct
* #param string $privkey
* #param string $remoteip
* #param string $challenge
* #param string $response
* #param array $extra_params an array of extra variables to post to the server
* #return ReCaptchaResponse
*/
function recaptcha_check_answer ($privkey, $remoteip, $challenge, $response, $extra_params = array())
{
if ($privkey == null || $privkey == '') {
die ("To use reCAPTCHA you must get an API key from <a href='http://recaptcha.net/api/getkey'>http://recaptcha.net/api/getkey</a>");
}
if ($remoteip == null || $remoteip == '') {
die ("For security reasons, you must pass the remote ip to reCAPTCHA");
}
//discard spam submissions
if ($challenge == null || strlen($challenge) == 0 || $response == null || strlen($response) == 0) {
$recaptcha_response = new ReCaptchaResponse();
$recaptcha_response->is_valid = false;
$recaptcha_response->error = 'incorrect-captcha-sol';
return $recaptcha_response;
}
$response = _recaptcha_http_post (RECAPTCHA_VERIFY_SERVER, "/verify",
array (
'privatekey' => $privkey,
'remoteip' => $remoteip,
'challenge' => $challenge,
'response' => $response
) + $extra_params
);
$answers = explode ("\n", $response [1]);
$recaptcha_response = new ReCaptchaResponse();
if (trim ($answers [0]) == 'true') {
$recaptcha_response->is_valid = true;
}
else {
$recaptcha_response->is_valid = false;
$recaptcha_response->error = $answers [1];
}
return $recaptcha_response;
}
/**
* gets a URL where the user can sign up for reCAPTCHA. If your application
* has a configuration page where you enter a key, you should provide a link
* using this function.
* #param string $domain The domain where the page is hosted
* #param string $appname The name of your application
*/
function recaptcha_get_signup_url ($domain = null, $appname = null) {
return "http://recaptcha.net/api/getkey?" . _recaptcha_qsencode (array ('domain' => $domain, 'app' => $appname));
}
function _recaptcha_aes_pad($val) {
$block_size = 16;
$numpad = $block_size - (strlen ($val) % $block_size);
return str_pad($val, strlen ($val) + $numpad, chr($numpad));
}
/* Mailhide related code */
function _recaptcha_aes_encrypt($val,$ky) {
if (! function_exists ("mcrypt_encrypt")) {
die ("To use reCAPTCHA Mailhide, you need to have the mcrypt php module installed.");
}
$mode=MCRYPT_MODE_CBC;
$enc=MCRYPT_RIJNDAEL_128;
$val=_recaptcha_aes_pad($val);
return mcrypt_encrypt($enc, $ky, $val, $mode, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");
}
function _recaptcha_mailhide_urlbase64 ($x) {
return strtr(base64_encode ($x), '+/', '-_');
}
/* gets the reCAPTCHA Mailhide url for a given email, public key and private key */
function recaptcha_mailhide_url($pubkey, $privkey, $email) {
if ($pubkey == '' || $pubkey == null || $privkey == "" || $privkey == null) {
die ("To use reCAPTCHA Mailhide, you have to sign up for a public and private key, " .
"you can do so at <a href='http://mailhide.recaptcha.net/apikey'>http://mailhide.recaptcha.net/apikey</a>");
}
$ky = pack('H*', $privkey);
$cryptmail = _recaptcha_aes_encrypt ($email, $ky);
return "http://mailhide.recaptcha.net/d?k=" . $pubkey . "&c=" . _recaptcha_mailhide_urlbase64 ($cryptmail);
}
/**
* gets the parts of the email to expose to the user.
* eg, given johndoe#example,com return ["john", "example.com"].
* the email is then displayed as john...#example.com
*/
function _recaptcha_mailhide_email_parts ($email) {
$arr = preg_split("/#/", $email );
if (strlen ($arr[0]) <= 4) {
$arr[0] = substr ($arr[0], 0, 1);
} else if (strlen ($arr[0]) <= 6) {
$arr[0] = substr ($arr[0], 0, 3);
} else {
$arr[0] = substr ($arr[0], 0, 4);
}
return $arr;
}
/**
* Gets html to display an email address given a public an private key.
* to get a key, go to:
*
* http://mailhide.recaptcha.net/apikey
*/
function recaptcha_mailhide_html($pubkey, $privkey, $email) {
$emailparts = _recaptcha_mailhide_email_parts ($email);
$url = recaptcha_mailhide_url ($pubkey, $privkey, $email);
return htmlentities($emailparts[0]) . "<a href='" . htmlentities ($url) .
"' onclick=\"window.open('" . htmlentities ($url) . "', '', 'toolbar=0,scrollbars=0,location=0,statusbar=0,menubar=0,resizable=0,width=500,height=300'); return false;\" title=\"Reveal this e-mail address\">...</a>#" . htmlentities ($emailparts [1]);
}
?>
This chapter from the reCaptcha documentation has information about customizing the look of reCaptcha.