I'm trying to add a Progress Bar to track the file Upload status of my Form. To upload files I use this Form code:
<form id="contact-form" action="awsUpload.php" method="post" name="frmImage" enctype="multipart/form-data">
<input class="file-input" type="file" style="width:100%;"autocomplete="off" name="ftp" accept="image/*, .zip, .rar, .bzip" onchange="this.form.submit();changeStyle()" class="file-up" id="fileFTP">
</form>
And this PHP code to manage the File Upload request.
<?php
require './aws/aws-autoloader.php';
use Aws\S3\S3Client;
use Aws\S3\Exception\S3Exception;
// AWS Info
$bucketName = '***';
$IAM_KEY = '***';
$IAM_SECRET = '***';
// Connect to AWS
try {
// You may need to change the region. It will say in the URL when the bucket is open
// and on creation. us-east-2 is Ohio, us-east-1 is North Virgina
$s3 = S3Client::factory(array(
'credentials' => array(
'key' => $IAM_KEY,
'secret' => $IAM_SECRET
),
'version' => 'latest',
'region' => 'eu-west-1'
));
}
catch (Exception $e) {
die("Error: " . $e->getMessage());
}
// For this, I would generate a unqiue random string for the key name. But you can do whatever.
//$target_file = 'f/' . basename($_FILES["ftp"]['tmp_name']); //ftp is file name at index.php
if (isset($_FILES["ftp"]) && $_FILES["ftp"]["error"] == 0) {
$mimeType = mime_content_type($_FILES["ftp"]["tmp_name"]);
$fileSize = $_FILES["ftp"]["size"];
if (strpos($mimeType, "image") === 0) {
if ($fileSize <= 1000 * 1024 * 1024) { //max image size
$target_dir = "i/";
// $strng = preg_replace("/[\s-]|\#/", "_", basename($_FILES["ftp"]["name"])); //Prima era solo "/[\s-]/"
$target_file = $target_dir . time() . rand(100, 999);
//$pathInS3 = 'https://s3.ap-south-1.amazonaws.com/' . $bucketName . '/' . $target_file;
// Add it to S3
try {
if (!file_exists('/tmp/tmpfile')) {
echo 3;
mkdir('/tmp/tmpfile');
}
$tempFilePath = '/tmp/tmpfile/' . basename($_FILES["ftp"]['name']);
$tempFile = fopen($tempFilePath, "w") or die("Error: Unable to open file.");
$fileContents = file_get_contents($_FILES["ftp"]['tmp_name']);
$tempFile = file_put_contents($tempFilePath, $fileContents);
$s3->putObject(array(
'Bucket' => $bucketName,
'Key' => $target_file,
'SourceFile' => $tempFilePath,
'StorageClass' => 'REDUCED_REDUNDANCY',
'ACL' => 'public-read'
));
$valPOutput = htmlspecialchars($target_file);
header('HTTP/1.1 303 See Other');
header('Location: http://example.com/result.php' . "?p=" . $valPOutput);
}
catch (S3Exception $e) {
die('Error:' . $e->getMessage());
}
catch (Exception $e) {
die('Error:' . $e->getMessage());
}
} else {
echo "image too big";
}
} elseif ($mimeType == "application/zip" || $mimeType == "application/x-rar-compressed" || $mimeType == "application/x-7z-compressed" || $mimeType == "application/x-bzip2") {
if ($fileSize <= 5000 * 1024 * 1024) { //max arch size
$target_dir = "f/";
//$strng = preg_replace("/[\s-]|\#/", "_", basename($_FILES["ftp"]["name"])); //Prima era solo "/[\s-]/"
$target_file = $target_dir . time() . rand(100, 999);
// $pathInS3 = 'https://s3.ap-south-1.amazonaws.com/' . $bucketName . '/' . $target_file;
// Add it to S3
try {
if (!file_exists('/tmp/tmpfile')) {
echo 3;
mkdir('/tmp/tmpfile');
}
$tempFilePath = '/tmp/tmpfile/' . basename($_FILES["ftp"]['name']);
$tempFile = fopen($tempFilePath, "w") or die("Error: Unable to open file.");
$fileContents = file_get_contents($_FILES["ftp"]['tmp_name']);
$tempFile = file_put_contents($tempFilePath, $fileContents);
$s3->putObject(array(
'Bucket' => $bucketName,
'Key' => $target_file,
'SourceFile' => $tempFilePath,
'StorageClass' => 'REDUCED_REDUNDANCY',
'ACL' => 'public-read'
));
$valPOutput = htmlspecialchars($target_file);
header('HTTP/1.1 303 See Other');
header('Location: http://example.com/result.php' . "?p=" . $valPOutput);
}
catch (S3Exception $e) {
die('Error:' . $e->getMessage());
}
catch (Exception $e) {
die('Error:' . $e->getMessage());
}
}else {
echo "arch too big";
}
}
}
?>
I've tried to do so adding event listeners to prevent submitting request, but when I upload a file, the website URL changes from https://example.com to https://example.com/awsUpload.php and the Progress Bar does not move and the Upload keeps going.
I'd like to receive some suggestions on how I can move or think to achieve that (the code I posted right now does not include any Progress bar test since I deleted the progress bar code cause it did not work).
EDIT DOWN HERE
Modified the form and added this new Script.
Right now the Load bar does work and the file gets uploaded, unfortunately I do not know why after the form gets submitted I do not get redirected to https://example.com/?p=****
<form id="contact-form" action="awsUpload.php" method="post" name="frmImage" enctype="multipart/form-data">
<input class="file-input" type="file" style="width:100%;"autocomplete="off" name="ftp" accept="image/*, .zip, .rar, .bzip" onchange="uploadFile(this.form)" class="file-up" id="fileFTP">
<progress id="upload-progress" value="0" max="100"></progress>
</form>
<script>
function uploadFile(form) {
var fileInput = form.querySelector('input[type="file"]');
var file = fileInput.files[0];
var formData = new FormData(form);
var xhr = new XMLHttpRequest();
xhr.open('POST', this.form, true);
xhr.upload.onprogress = function(e) {
if (e.lengthComputable) {
var percentComplete = (e.loaded / e.total) * 100;
var progressBar = form.querySelector('progress');
progressBar.value = percentComplete;
}
};
xhr.onload = function() {
if (xhr.status == 200) {
// File uploaded successfully
alert('success')
} else {
// An error occurred during the upload
}
};
xhr.send(formData);
}
</script>
Extra: I tried to ad in the action of if (xhr.status == 200) to redirect to a certain webpage with window.location but I'm missing the $valPOutput from the awsUpload.php and do not know how to get it.
Related
window.addEventListener("load", () => {
var uploader = new plupload.Uploader({
runtimes: "html5",
browse_button: "upload",
url: "../upload.php",
chunk_size: "10mb", // <<<<<<< Here is my problem
filters: {
max_file_size: "100gb",
.... THIS CODE HERE DOESN'T MATTER .....
});
This is my upload.php
function verbose ($ok=1, $info="") {
if ($ok==0) { http_response_code(400); }
exit(json_encode(["ok"=>$ok, "info"=>$info]));
}
if (empty($_FILES) || $_FILES["file"]["error"]) {
verbose(0, "Failed to move uploaded file.");
}
$filePath = __DIR__ . DIRECTORY_SEPARATOR . "videos";
if (!file_exists($filePath)) { if (!mkdir($filePath, 0777, true)) {
verbose(0, "Failed to create $filePath");
}}
$fileName = isset($_REQUEST["name"]) ? $_REQUEST["name"] : $_FILES["file"]["name"];
$filePath = $filePath . DIRECTORY_SEPARATOR . $fileName;
$dateformat = date("Y-m-d-H:i:s");
$fileSize = $_FILES["file"]["size"]; // <<<<< HERE IS MY PROBLEM
$title = pathinfo($fileName,PATHINFO_FILENAME);
$chunk = isset($_REQUEST["chunk"]) ? intval($_REQUEST["chunk"]) : 0;
$chunks = isset($_REQUEST["chunks"]) ? intval($_REQUEST["chunks"]) : 0;
$out = #fopen("{$filePath}.part", $chunk == 0 ? "wb" : "ab");
if ($out) {
$in = #fopen($_FILES['file']['tmp_name'], "rb");
if ($in) {
while ($buff = fread($in, 4096)) {
fwrite($out, $buff);
}
}else{
echo "err";
}
#fclose($in);
#fclose($out);
#unlink($_FILES['file']['tmp_name']);
}else{
verbose(0, "Failed to open output stream");
}
if (!$chunks || $chunk == $chunks - 1) {
$rename = 'videos/'.generateKey($pdo); // simple function to generate random string ( 123asdjjn124 and so on)
$databaseName = str_replace('videos/','', $rename); // remove videos/ from the string
rename("{$filePath}.part", $rename);
$stmt = $pdo->prepare("INSERT INTO videos(title,size,date,link) VALUES(:title,:size,:date,:link)");
$stmt->bindParam(':title',$title,PDO::PARAM_STR);
$stmt->bindParam(':size',$fileSize,PDO::PARAM_STR); // <<<<< HERE IS MY PROBLEM
$stmt->bindParam(':date',$dateformat,PDO::PARAM_STR);
$stmt->bindParam(':link',$databaseName,PDO::PARAM_STR);
$stmt->execute();
}
verbose(1, "Upload OK");
Now when I upload a file, everything is entered beautifully but the size of the "chunk_size" is always entered instead of the correct size of the file. Does anyone have an idea why this is so? It also makes no difference if I change the file size, it always takes the "chunk_size".
Any advice is helpful
Here I have another screenshot to illustrate how I mean it. https://prnt.sc/QW-zXtrb6RuY
So basically i build an webpage(php+js) on xampp that lets users fill a form and in that form they can upload multiple images.
The site was working fine so i upload it to production on the server with IIS8.
The form works great but i cant upload or view the images i uploaded.
The images are being uploaded to a samba drive, in xampp i had no issue it worked how it was suppose too on IIS I'm getting an error saying i don't have permissions. i don't know what I'm doing wrong
this is the code to get the images
<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST' && !empty($_POST['id'])){
$id = $_POST['id'];
$directory = '\\\\server\\'.$id.'\\';
$directory = '\\\\server\\'.$id.'\\';
$local = glob("" . $directory . "{*.jpg,*.gif,*.png}", GLOB_BRACE);
$img_arr = array();
if($local){
$x=1;
}else{
$x=0;
}
foreach($local as $item)
{
$image = $item;
$imageData = base64_encode(file_get_contents($image));
$src = 'data: '.mime_content_type($image).';base64,'.$imageData;
$img_arr [] = array('mime'=> mime_content_type($image),'imgDt'=> $imageData);
}
}
if ($x==0){
$response = [
'status'=>'falhou',
'values' => $local
];
}else{
$response = [
'status'=>'sucesso',
'values' => $img_arr
];
}
header('Content-Type: application/json');
echo json_encode($response);
?>
and this is the code to add images
if (!file_exists('\\\\server\\'.$tmstp)) {
mkdir('\\\\server\\'.$tmstp);
}
$uploadDir = '\\\\server\\'.$tmstp.'\\';
if(!empty($_FILES['anex'])){
foreach ($_FILES['anex']['name'] as $key=>$ficheiro) {
$fileName = basename($_FILES['anex']['name'][$key]);
$tmpname = $_FILES['anex']['tmp_name'][$key];
$targetFilePath = $uploadDir . $fileName;
$fileType = pathinfo($targetFilePath, PATHINFO_EXTENSION);
$allowTypes = array('jpg', 'png', 'jpeg', 'gif');
if(in_array($fileType, $allowTypes)){
if(file_exists($targetFilePath)) {
//chmod($targetFilePath,0755); //Change the file permissions if allowed
unlink($targetFilePath); //remove the file
}
if(move_uploaded_file($tmpname, $targetFilePath)){
$uploadedFile = $fileName;
if ($i=0){
$anex=$fileName;
$i++;
$uploadStatus = 1;
$hf=true;
}
else{
$anex=$anex .';' . $fileName;
$uploadStatus = 1;
$hf=true;
$rspimg = 'Upload fotos com sucesso';
}
}else{
$uploadStatus = 0;
$rspimg = 'Ouve um erro com o UPLOAD das imagens';
}
}else{
$uploadStatus = 0;
$rspimg = 'Só JPG, JPEG, PNG ou GIF';
}
}
}else{
$hf = false;
}
i already tried creating a virtual folder on IIS and it still doesn't work
I am trying to perform a Post request to store some dummy data to my database. The data set consist of three text fields and a file.
Following the Slim 3 File Upload Documentation I created my service which works perfectly.
Here's my service code:
<?php
use \Psr\Http\Message\ServerRequestInterface as Request;
use \Psr\Http\Message\ResponseInterface as Response;
use Slim\Http\UploadedFile;
$container = $app->getContainer();
$container['upload_directory'] = __DIR__ . '/uploads/';
$app->post('/np/register',function(Request $request, Response $response){
$np_name = $request->getParam('np_name');
$np_language = $request->getParam('np_language');
$uploadedFiles = $request->getUploadedFiles();
$upload_folder = '/uploads/';
$directory = $this->get('upload_directory');
$np_image_path = $uploadedFiles['np_image_path'];
$np_active_status = $request->getParam('np_active_status');
$register_date = date('Y/m/d H:i:s');
//Getting the server ip
$server_ip = gethostbyname(gethostname());
try
{
$np_name_check = preg_match('~^[A-Za-z ]{3,20}$~i', $np_name);
$np_language_check = preg_match('~^[A-Za-z_]{3,20}$~i', $np_language);
$np_active_status_check = preg_match('/^[0-1]{1}$/', $np_active_status);
if($np_name_check>0 && $np_language_check>0 && $np_active_status_check>0 && isset($np_name) && isset($np_language) &&
isset($np_active_status) && isset($np_image_path))
{
$get_filename = moveUploadedFile($directory, $np_image_path);
$ServerURL = 'http://'.$server_ip.'/np_console/src/routes'.$upload_folder.$get_filename;
$np_image_path = $ServerURL;
$sql = "INSERT INTO np_registration (np_name,np_language,np_image_path,np_active_status,np_register_date) VALUES (:np_name,:np_language,:np_image_path,:np_active_status,:register_date)";
try
{
//Get DB Object
$db = new db();
//Connect to database
$db = $db->connect();
$stmt = $db->prepare($sql);
$stmt->bindParam(':np_name', $np_name);
$stmt->bindParam(':np_language', $np_language);
$stmt->bindParam(':np_image_path', $np_image_path);
$stmt->bindParam(':np_active_status', $np_active_status);
$stmt->bindParam(':register_date', $register_date);
$stmt->execute();
echo '{"notice":{"respnse":"NetPicks Added Successfully"}';
}
catch(PDOException $e)
{
echo '{"error":{"text":'. $e->getMessage() .'}}';
}
}
else{
echo '{"error":{"respnse":"\nInvalid Data Entry"}';
}
}
catch(PDOException $e) {
echo '{"error":{"text":'. $e->getMessage() .'}}';
}
});
function moveUploadedFile($directory, UploadedFile $uploadedFile)
{
$extension = pathinfo($uploadedFile->getClientFilename(), PATHINFO_EXTENSION);
$basename = bin2hex(random_bytes(8));
$filename = sprintf('%s.%0.8s', $basename, $extension);
$uploadedFile->moveTo($directory . DIRECTORY_SEPARATOR . $filename);
return $filename;
}
?>
My Post request via Postman works as required and I am able to insert values to my db.
Postman Response
But when I try to perform the POST request from my web page it fails. On using the var_dump I found out that $uploadedFiles always returns array(0).
Post Service call:
export default function NP_Registration_Service(type, np_name, np_language, np_image_path, np_active_status){
let BaseUrl = 'http://localhost/np_console/public/index.php';
let formData = new FormData();
formData.append('np_name', np_name);
formData.append('np_language', np_language);
formData.append('np_image_path', np_image_path);
formData.append('np_active_status', np_active_status);
return new Promise((resolve,reject) => {
fetch(BaseUrl+type,{
method: 'POST',
body: formData
})
.then((response) => {
var resText = response.text();
console.log("The resText");
console.log(resText);
})
.catch((error) => {
reject(error);
});
});
}
Here's the response with var_dump($uploadedFiles) which returns array(0).
Console Output
I have looked into this but it didn't provide any help.
So am I making a mistake with the service call?
As suggested by Karol Samborski adding
var fileField = document.querySelector("input[type='file']");
formData.append('np_image_path', fileField.files[0]);
to the Post service call(fetch request) resolved the issue.
I am developing a smart tv app that plays live streams. App itself works fine, when i provide a valid xml playlist to it.
But when i use php to generate xml file (wich also generates fine), it doesnt work.
I get an error:
TypeError: 'null' is not an object (evaluating 'this.XHRObj.responseXML.documentElement')
Here is my php file that generates videoList.xml, it works 100%.
In short words, this script checks if MAC address in database, and if it is, then it writes videoList.xml with walid live streaming links.
SamsungAPI.php
<?php
$MAC = $_GET['MAC'];
require_once('../config.php');
//Remove brackets form array
$_INFO = preg_replace('/[{}]/', '', $_INFO);
$mysqli = new mysqli($_INFO['host'], $_INFO['db_user'], $_INFO['db_pass'], $_INFO['db_name']);
if (mysqli_connect_errno()) {
printf("Connect failed: %s\n", mysqli_connect_error());
exit();
}
$sql="SELECT * FROM users WHERE admin_notes = '$MAC' ";
$rs=$mysqli->query($sql);
$rows=mysqli_num_rows($rs);
if ($rows == 1) {
//MAC FOUND
$row = mysqli_fetch_array($rs);
$username = $row['username'];
$password = $row['password'];
$file = "videoList.xml";
$txt_file = file_get_contents('http://' . $_SERVER['HTTP_HOST'] . '/get.php?type=starlivev3&username=' . $username . '&password=' . $password . '&output=hls');
$rows = explode("\n", $txt_file);
if(empty($rows[count($rows)-1])) {
unset($rows[count($rows)-1]);
$rows=array_map('trim',$rows);
}
$handle = fopen($file, "w+") or die('Could not open file');
fwrite($handle, "<?xml version=\"1.0\"?>"."\n");
fwrite($handle, "<rss version=\"2.0\">"."\n");
fwrite($handle, "<channel>"."\n");
foreach($rows as $row => $data)
{
//get row data
$row_data = explode(',', $data);
//replace _ with spaces
$row_data[0] = str_replace('_', ' ', $row_data[0]);
//generate playlist content
fwrite($handle, "<item>"."\n");
fwrite($handle, "<title>{$row_data[0]}</title>"."\n");
fwrite($handle, "<link>{$row_data[1]}</link>"."\n");
fwrite($handle, "<description> Reserved for EPG </description>"."\n");
fwrite($handle, "</item>"."\n");
}
fwrite($handle, "</channel>"."\n");
fwrite($handle, "</rss>");
fclose($handle);
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.basename($file));
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
readfile($file);
exit;
} else {
//MAC NOT FOUND
echo "MAC NOT FOUND";
}
mysqli_close($mysqli); // Closing Connection
?>
Then in samsung smart tv videoplayer app, i have xml parser like this:
Server.js
var Server =
{
/* Callback function to be set by client */
dataReceivedCallback : null,
XHRObj : null,
url : "http://myvalidhost.com/samsungAPI.php?MAC=02000027000b"
}
Server.init = function()
{
var success = true;
if (this.XHRObj)
{
this.XHRObj.destroy(); // Save memory
this.XHRObj = null;
}
return success;
}
Server.fetchVideoList = function()
{
if (this.XHRObj == null)
{
this.XHRObj = new XMLHttpRequest();
}
if (this.XHRObj)
{
this.XHRObj.onreadystatechange = function()
{
if (Server.XHRObj.readyState == 4)
{
Server.createVideoList();
}
}
this.XHRObj.open("GET", this.url, true);
this.XHRObj.send(null);
}
else
{
alert("Failed to create XHR");
}
}
Server.createVideoList = function()
{
if (this.XHRObj.status != 200)
{
Display.status("XML Server Error " + this.XHRObj.status);
}
else
{
var xmlElement = this.XHRObj.responseXML.documentElement;
if (!xmlElement)
{
alert("Failed to get valid XML");
}
else
{
// Parse RSS
// Get all "item" elements
var items = xmlElement.getElementsByTagName("item");
var videoNames = [ ];
var videoURLs = [ ];
var videoDescriptions = [ ];
for (var index = 0; index < items.length; index++)
{
var titleElement = items[index].getElementsByTagName("title")[0];
var descriptionElement = items[index].getElementsByTagName("description")[0];
var linkElement = items[index].getElementsByTagName("link")[0];
if (titleElement && descriptionElement && linkElement)
{
videoNames[index] = titleElement.firstChild.data;
if(linkElement.firstChild.data.substring(0,4) !="http"){
alert("asdasdasd "+linkElement.firstChild.data.substring(0,4));
var rootPath = window.location.href.substring(0, location.href.lastIndexOf("/")+1);
var Abs_path = unescape(rootPath).split("file://")[1]+linkElement.firstChild.data;
videoURLs[index] = Abs_path;
}
else{
videoURLs[index] = linkElement.firstChild.data;
}
videoDescriptions[index] = descriptionElement.firstChild.data;
}
}
Data.setVideoNames(videoNames);
Data.setVideoURLs(videoURLs);
Data.setVideoDescriptions(videoDescriptions);
if (this.dataReceivedCallback)
{
this.dataReceivedCallback(); /* Notify all data is received and stored */
}
}
}
}
Does anyone have any idea why doesnt it accept my generated xml file?
Regards
M
I figured it out, in php headers content type was wrong.
Changed
header('Content-Type: application/octet-stream');
to
header('Content-Type: application/xml');
Now it works perfect!
I am trying to reach multiple file/image upload with php, but what i get is only one file in my upload folder, form is sending by ajax. This is my code:
<input type='file' id='_file' multiple="multiple" name="SelectedFile[]">
<input type='button' id='_submit' value='Upload!'>
and PHP
<?php
// Output JSON
function outputJSON($msg, $status = 'error'){
header('Content-Type: application/json');
die(json_encode(array(
'data' => $msg,
'status' => $status
)));
}
$count = 0;
...
// Success!
foreach ($_FILES['SelectedFile']['name'] as $f => $name) {
outputJSON('File uploaded successfully to "' . 'upload/' . $_FILES['SelectedFile']['name'][0] . '".', 'success');
$count ++;
}
JS
var data = new FormData();
data.append('SelectedFile', _file.files[0]);
var request = new XMLHttpRequest();
request.onreadystatechange = function(){
if (request.readyState == 4){
try {
var resp = JSON.parse(request.response);
} catch (e){
var resp = {
status: 'error',
data: 'Unknown error occurred: [' + request.responseText + ']'
};
}
console.log(resp.status + ': ' + resp.data);
}
};
request.upload.addEventListener('progress', function(e){
_progress.style.width = Math.ceil(e.loaded/e.total) * 100 + '%';
}, false);
request.open('POST', 'upload.php');
request.send(data);
i still have Unknown error occurred: []
Remove the die call from the outputJSON function and use echo instead, it's terminating the script in the first loop of the foreach.
Update:
Assuming that the files are correctly uploaded and stored in $_FILES array, this code output should be parse-able by js:
header('Content-Type: application/json');
$output = array();
foreach ($_FILES['SelectedFile'] as $f => $file) {
$output []= array(
'data' => 'File uploaded successfully to "' . 'upload/' . $file['name'],
'status' => 'success',
);
}
echo json_encode($output);