I'm getting really confused here. So here's whats going on in my project. The user clicks download then select directory to save the file, the file will be a zip file. After that I want to extract that zip file in the same directory the users chooses. Is this even possible in one script?
Here is my php code
<?php
require_once('connect.php');
// Get real path for our folder
$rootPath = realpath($_GET['uniq']);
// Name of the zip derive from the database
$zipname = $_GET['name'] . '.zip';
// Initialize archive object
$zip = new ZipArchive();
$zip->open($zipname, ZipArchive::CREATE | ZipArchive::OVERWRITE);
// Create recursive directory iterator
/** #var SplFileInfo[] $files */
$files = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($rootPath),
RecursiveIteratorIterator::LEAVES_ONLY
);
foreach ($files as $name => $file)
{
// Skip directories (they would be added automatically)
if (!$file->isDir())
{
// Get real and relative path for current file
$filePath = $file->getRealPath();
$relativePath = substr($filePath, strlen($rootPath) + 1);
// Add current file to archive
$zip->addFile($filePath, $relativePath);
}
}
// Zip archive will be created only after closing object
$zip->close();
header('Content-Type: application/zip');
header('Content-disposition: attachment; filename='.$zipname);
header('Content-Length: ' . filesize($zipname));
readfile($zipname);
?>
If its not possible another question. Is it possible to let user choose a zip file then after that it will be extracted at some client directory ie. C://xamp/extracthere/ using javascript.
Once the user has downloaded the file to their machine, it's beyond your control. You can't force them to unzip it, or do anything else with it for that matter.
Imagine if you could control the files on a user's local disk, it would be a hacker's dream. This is impossible using both PHP and JavaScript, for similar reasons in each case.
Related
I have a weird situation:
I get data from a Postgres database, and from that data, I create a table in a website, using Grid.js. Each line has a "Download" button, that takes 2 arguments from that table entry and send them to a function. Originally, that function would make a XHR request to a php file, that gets files from another DB, creates a ZIP file, and should send it to the user, with readfile().
I now discovered that this is not possible. XHR does not allow downloads for safety reasons.
I could do something using window.location to call the PHP file, and get the download, but I am dealing with hundreds of files, so I cannot write hundreds of PHP files to get the data individually. I could, but it would be very hard to maintain and manage all those files, and it feels unprofessional.
Right now, I can:
Send the data from JS to PHP, using POST;
Using those two variables, fetch the data from another Postgres server;
Use those files and create a ZIP file (The ZIP files cannot be stored permanently in the server, because of storage restrictions. A cronjob in the server will clean the files eventually)
I need to:
Send the ZIP to to the user;
Maintain the simplest code possible, in a way that I can feed 2 variables and it just works, without needing a PHP file for each table line (if that makes sense)
The current code is:
Javascript
const getData = (schema, table) => {
const xhr = new XMLHttpRequest();
xhr.open('POST', 'php/get_data.php', true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
let packg = {
schema: schema,
table: table
};
const packgJSON = JSON.stringify(packg);
// Vanilla JS XHR requires this formatting to send the data
const data = new URLSearchParams({'content': packgJSON});
xhr.send(data);
};
PHP
<?php
// File with connection info
$config = include('config.php');
// Connection info
$host = $config['host'];
$port = $config['port'];
$database = $config['database'];
$username = $config['username'];
$password = $config['password'];
// POST reception
$packg = json_decode($_POST['content']);
$schema = $packg->schema;
$table = $packg->table;
// File info and paths
$filename = $table;
$rootDir = "tempData/";
$fileDir = $filename . "/";
$filePath = $rootDir . $fileDir;
$completeFilePath = $filePath . $filename;
$shpfile = $filename . ".shp";
$zipped = $filename . ".zip";
$zipFile = $completeFilePath . ".zip";
// Function to send the file (PROBLEM - THIS DOES NOT WORK WITH XHR)
function sendZip($zipFile) {
$zipName = basename($zipFile);
header("Content-Type: application/zip");
header("Content-Disposition: attachment; filename=$zipName");
header("Content-Length: " . filesize($zipFile));
ob_flush();
flush();
readfile($zipFile);
};
// Send the zip if it's already available (NOT PROBLEMATIC)
if (file_exists($zipFile)) {
sendZip($zipFile);
};
// Get shapefile, zip it and send it, if not available (NOT PROBLEMATIC)
if (!file_exists($zipFile)) {
// Get files
exec("mkdir -p -m 777 $filePath");
exec("pgsql2shp -h $host -p $port -u $username -P $password -g geom -k -f $completeFilePath $database $schema.$table");
// ZIP the files
$zip = new ZipArchive;
if ($zip -> open($zipFile, ZipArchive::CREATE) === TRUE) {
$handlerDir = opendir($filePath);
// Iterates all files inside folder
while ($handlerFile = readdir($handlerDir)) {
// If the files are indeed files, and not directories
if (is_file($filePath . $handlerFile) && $handlerFile != "." && $handlerFile != "..") {
// Zip them
$zip -> addFile($filePath . $handlerFile, $fileDir . $handlerFile);
};
};
// Close the file
$zip -> close();
};
sendZip($zipFile);
};
?>
As pointed out by #epascarello here, a simple GET request solves this.
Even though I was afraid of not using POST because of an SQL injection attack, the variables pass through a pgsql2shp program, and that only accepts a valid schema and table names, so no need to worry about that as much.
I am currently using this KISS code, and it works:
const getData = (schema, table) => {
window.location='php/get_data.php?schema=' + schema + '&table=' + table;
};
In PHP, it's only needed a small change from the POST reception to a GET reception. The variables are already separated, no need to decode anything:
$schema = $_GET['schema'];
$table = $_GET['table'];
This goes to show that sometimes, we look so deep into a problem that the solution is right in front of us.
I'm working on an internal application where user uploads some images, uses them and at the end downloads all the files as a package.
I'm a really beginner to PHP so found a code that creates a zip of uploaded images.
<?php
$dir = 'uploads/';
$zip_file = 'file.zip';
// Get real path for our folder
$rootPath = realpath($dir);
// Initialize archive object
$zip = new ZipArchive();
$zip->open($zip_file, ZipArchive::CREATE | ZipArchive::OVERWRITE);
// Create recursive directory iterator
/** #var SplFileInfo[] $files */
$files = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($rootPath),
RecursiveIteratorIterator::LEAVES_ONLY
);
foreach ($files as $name => $file)
{
// Skip directories (they would be added automatically)
if (!$file->isDir())
{
// Get real and relative path for current file
$filePath = $file->getRealPath();
$relativePath = substr($filePath, strlen($rootPath) + 1);
// Add current file to archive
$zip->addFile($filePath, $relativePath);
}
}
// Zip archive will be created only after closing object
$zip->close();
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.basename($zip_file));
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($zip_file));
readfile($zip_file);
?>
Now there is a textarea which has a code.
I want to add that textarea's content to zip as html.
You should save textarea's content as separated .HTML file in $dir = 'uploads/';. For this you can use file_put_contents method (remember about correct file path). After ZIP creation you can remove this file.
I am trying to create and save a file to the root directory of my site, but I don't know where its creating the file as I cannot see any. And, I need the file to be overwritten every time, if possible.
Here is my code:
$content = "some text here";
$fp = fopen("myText.txt","wb");
fwrite($fp,$content);
fclose($fp);
How can I set it to save on the root?
It's creating the file in the same directory as your script. Try this instead.
$content = "some text here";
$fp = fopen($_SERVER['DOCUMENT_ROOT'] . "/myText.txt","wb");
fwrite($fp,$content);
fclose($fp);
If you are running PHP on Apache then you can use the enviroment variable called DOCUMENT_ROOT. This means that the path is dynamic, and can be moved between servers without messing about with the code.
<?php
$fileLocation = getenv("DOCUMENT_ROOT") . "/myfile.txt";
$file = fopen($fileLocation,"w");
$content = "Your text here";
fwrite($file,$content);
fclose($file);
?>
This question has been asked years ago but here is a modern approach using PHP5 or newer versions.
$filename = 'myfile.txt'
if(!file_put_contents($filename, 'Some text here')){
// overwriting the file failed (permission problem maybe), debug or log here
}
If the file doesn't exist in that directory it will be created, otherwise it will be overwritten unless FILE_APPEND flag is set.
file_put_contents is a built in function that has been available since PHP5.
Documentation for file_put_contents
fopen() will open a resource in the same directory as the file executing the command. In other words, if you're just running the file ~/test.php, your script will create ~/myText.txt.
This can get a little confusing if you're using any URL rewriting (such as in an MVC framework) as it will likely create the new file in whatever the directory contains the root index.php file.
Also, you must have correct permissions set and may want to test before writing to the file. The following would help you debug:
$fp = fopen("myText.txt","wb");
if( $fp == false ){
//do debugging or logging here
}else{
fwrite($fp,$content);
fclose($fp);
}
This is a strange request I suppose, but I have a directory full of txt files. For example:
- david_smith_interview.txt -
- beth_martin_interview.txt -
- sally_smithart_interview.txt
The contents of these text files are a link to their interview in an mp3 format, for example, if you open the file david_smith_interview.txt, it is simply this:
http://www.interviews/employees/david_smith.mp3
All of the other text files follow the same format. They are simply links to their mp3 interview.
I am trying to use something like below to list the text files:
<?php
$directory = "/employees/";
$phpfiles = glob($directory . "*.txt");
foreach($phpfiles as $phpfile)
{
echo $phpfile; // This will list the files by name
// How can I output something to reflect this:
// david_smith_interview
}
?>
So I am asking is it possible that the text file can be "read" and used as the actual link?
Any thoughts?
Replace _interview.txt with .mp3
echo "" . str_replace(".txt", "", $phpfile). "\";
Since those are .txt files you can just read them one by one to a variable and then echo the result in a for-loop.
In pseudo:
$paths fetch_paths()
$urls = array();
foreach($paths as $path)
{
$url=fopen($path);
array_push($urls,fgets(url)); // Assuming there's only one link per file and it is on one line.
}
foreach($urls as $url)
{
echo <Your formatted link here>
}
im looking to make a web player from scratch so I can control my music from my phone. I've got a listing of all files within a folder done, but I need to get it to list the files within the subfolders of the main folder.
So sort of something like \Path\ - Shows all in \Path\ and \Path\subs\ shows the contents of all subfolders.
This is the code that I have written to allow me to search a folder for .mp3 files, but I cannot pin the way to search in subfolders as well.
$.ajax({
url: "music/",
success: function(data){
$(data).find("a:contains(.mp3)").each(function(){
var files = $(this).text().replace(/ /g, '');
files = $(this).text().replace(/.mp3/,'');
$('<p></p>').html(files).appendTo('#displayer');
$('#displayer > p:nth-child(odd)').css('background-color','#DDD');
});
}
});
Many thanks in advance
This is my solution in PHP
<?php
// your mp3 dir
$dir = "dir/";
$result = array();
if(is_dir($dir)){
$iterator = new RecursiveDirectoryIterator($dir);
foreach(new RecursiveIteratorIterator($iterator, RecursiveIteratorIterator::CHILD_FIRST) as $file){
$ext = pathinfo($file, PATHINFO_EXTENSION);
if("mp3"==$ext){
$result[] = $file->getPathName();
}
}
// you can echo json_encode(yourMp3Path) here.
var_dump($result);
}