PHP editing text file on remote server not working - php

I have multiple sites, and have a text file on our main site with a list of domains to whitelist. I want to be able to edit this global file from each of the websites.
I have a couple of problems that I'm running into:
file_exists() and ftp_delete() are not finding the file even though it exists on the remote server.
ftp_fput() is adding a blank text file in the correct place with a zero filesize.
Here is my code:
// Check if we are updating the whitelist
if(isset($_POST['Submit'])){
// Make sure we have something to add or remove
if (isset($_POST['update']) && $_POST['update'] != '') {
// Get the text we need to add or remove
$add_or_remove_this = $_POST['update'];
eri_update_global_whitelist( $add_or_remove_this, 'add' );
// Say it was done
echo '<br>Script Completed...<br>';
}
}
echo '<form method="post">
<textarea name="update" cols="50" rows="10"></textarea><br><br>
<input name="Submit" type="submit" value="Update"/>
</form>';
function eri_update_global_whitelist( $string, $add_or_remove = 'add' ) {
// Validate the string
$domains = explode( ',', str_replace(' ', '', strtolower($string)) );
print_r($domains); // <-- WORKS AS EXPECTED
// Add invalid domains here
$invalid = [];
// Cycle
foreach ($domains as $key => $domain) {
// Check if it contains a dot
if (strpos($domain, '.') === false) {
// If not, remove it
unset($domains[$key]);
// Add it to invalid array'
$invalid[] = $domain;
}
}
print_r($domains); // <-- WORKS AS EXPECTED
// Only continue if we have domains to work with
if (!empty($domains)) {
// The whitelist filename
$filename = 'email_domain_whitelist.txt';
// File path on remote server
$file_url = 'https://example.com/eri-webtools-plugin/data/'.$filename;
// Get the file content
$file_contents = file_get_contents( $file_url );
// Only continue if we found the file
if ($file_contents) {
// Explode the old domains
$old_domains = explode( ',', str_replace(' ', '', $file_contents) );
print_r($old_domains); // <-- WORKS AS EXPECTED
// Are we adding or removing
if ($add_or_remove == 'add') {
// Merge the arrays without duplicates
$new_domains = array_unique (array_merge ($old_domains, $domains));
} else {
// Loop through them
foreach ($old_domains as $key => $old_domain) {
// Check if it matches one of the new domains
if (in_array($old_domain, $domains)) {
// If so, remove it
unset($old_domains[$key]);
}
}
// Change var
$new_domains = $old_domains;
}
print_r($new_domains); // <-- WORKS AS EXPECTED
// Include the ftp configuration file
require_once $_SERVER['DOCUMENT_ROOT'].'/wp-content/plugins/eri-webtools-plugin/ftp_config.php';
// Establishing ftp connection
$ftp_connection = ftp_connect($ftp_server)
or die("<br>Could not connect to $ftp_server");
// If connected
if ( $ftp_connection ) {
// Log in to established connection with ftp username password
$login = ftp_login( $ftp_connection, $ftp_username, $ftp_userpass );
// If we are logged in
if ( $login ){
echo '<br>Logged in successfully!'; // <-- WORKS AS EXPECTED
// Make passive
ftp_pasv($ftp_connection, true);
// File path to delete
$file_to_delete = 'https://example.com/eri-webtools-plugin/data/'.$filename; // <-- NOT SURE HOW TO USE ABSOLUTE PATH ON REMOTE SERVER ??
// Delete the old file
if (file_exists($file_to_delete)) {
if (ftp_delete($ftp_connection, $file_to_delete)) {
echo '<br>Successfully deleted '.$filename;
} else {
echo '<br>There was a problem while deleting '.$filename;
}
} else {
echo '<br>File does not exist at: '.$file_to_delete; // <-- RETURNS
}
// Create a new file
$open = fopen($filename, 'r+');
// If we didn't die, let's implode it
$new_domain_string = implode(', ', $new_domains);
print_r('<br>'.$new_domain_string); // <-- WORKS AS EXPECTED
// Write to the new text file
if (fwrite( $open, $new_domain_string )) {
echo '<br>Successfully wrote to file.'; // <-- RETURNS
} else {
echo '<br>Cannot write to file.';
}
// Add the new file
if (ftp_fput($ftp_connection, '/eri-webtools-plugin/data/2'.$filename, $open, FTP_ASCII)) {
echo '<br>Successfully uploaded '.$filename; // <-- RETURNS
} else {
echo '<br>There was a problem while uploading '.$filename;
}
} else {
echo '<br>Could not login...';
}
// Close the FTP connection
if(ftp_close($ftp_connection)) {
echo '<br>Connection closed Successfully!'; // <-- RETURNS
} else {
echo '<br>Connection could not close...';
}
} else {
echo '<br>Could not connect...';
}
} else {
echo '<br>Could not find the file...';
}
} else {
echo '<br>No valid domains to add or remove...';
}
// Check for invalid domains
if (!empty($invalid)) {
echo '<br>Invalid domains found: '.implode(', ', $invalid);
}
}

Finally figured it out. I ditched ftp_fput() and replaced it with ftp_put(). Then I referred to the temporary file location on the local server instead of the fopen() like so:
ftp_put($ftp_connection, '/eri-webtools-plugin/data/'.$filename, $filename, FTP_ASCII)
So to explain what's going on (in case someone else runs into this):
// Name the temporary path and file, preferably the same name as what you want to call it.
// The path doesn't need to be specified. It just gets temporarily stored at the root and then deleted afterwards.
$filename = 'filename.txt';
// Create a new file by opening one that doesn't exist
// This will be temporarily stored on the local server as noted above
$fp = fopen($filename, 'w+');
// Write to the new file
fwrite( $fp, 'Text content in the file' );
// Add the file where you want it
ftp_put($ftp_connection, '/desination_folder/'.$filename, $filename, FTP_ASCII);
// Close the file
fclose($fp);
I ended up finding out that using ftp_put() will replace a file if it already exists, so there is no need to delete the old one like I was trying to.

Related

PHP file_exists With Contents Instead of Name?

Is there a function built into PHP that acts like file_exists, but given file contents instead of the file name?
I need this because I have a site where people can upload an image. The image is stored in a file with a name determined by my program (image_0.png image_1.png image_2.png image_3.png image_4.png ...). I do not want my site to have multiple images with the same contents. This could happen if multiple people found a picture on the internet and all of them uploaded it to my site. I would like to check if there is already a file with the contents of the uploaded file to save on storage.
This is how you can compare exactly two files with PHP:
function compareFiles($file_a, $file_b)
{
if (filesize($file_a) == filesize($file_b))
{
$fp_a = fopen($file_a, 'rb');
$fp_b = fopen($file_b, 'rb');
while (($b = fread($fp_a, 4096)) !== false)
{
$b_b = fread($fp_b, 4096);
if ($b !== $b_b)
{
fclose($fp_a);
fclose($fp_b);
return false;
}
}
fclose($fp_a);
fclose($fp_b);
return true;
}
return false;
}
If you keep the sha1 sum of each file you accept you can simply:
if ($known_sha1 == sha1_file($new_file))
You can use a while loop to look look through the contents of all of your files. This is shown in the example below :
function content_exists($file){
$image = file_get_contents($file);
$counter = 0;
while(file_exists('image_' . $counter . '.png')){
$check = file_get_contents('image_' . $counter . '.png');
if($image === $check){
return true;
}
else{
$counter ++;
}
}
return false;
}
The above function looks through all of your files and checks to see if the given image matches an image that is already stored. If the image already exists, true is returned and if the image does not exist false is returned. An example of how you can use this function shown is below :
if(content_exists($_FILES['file']['tmp_name'])){
// upload
}
else{
// do not upload
}
You could store hashed files in a .txt file separated by a \n so that you could use the function below :
function content_exists($file){
$file = hash('sha256', file_get_contents($file));
$files = explode("\n", rtrim(file_get_contents('files.txt')));
if(in_array($file, $files)){
return true;
}
else{
return false;
}
}
You could then use it to determine whether or not you should save the file as shown below :
if(content_exists($_FILES['file']['tmp_name'])){
// upload
}
else{
// do not upload
}
Just make sure that when a file IS stored, you use the following line of code :
file_put_contents('files.txt', hash('sha256', file_get_contents($file)) . "\n");

Upload fails "move uploaded file"

First off, the upload folder is given 777, and my old upload script works, so the server accepts files. How ever this is a new destination.
I use krajee bootstrap upload to send the files. And I receive a Jason response. The error seems to be around move uploaded file. I bet it's a simple error from my side, but I can't see it.
<?php
if (empty($_FILES['filer42'])) {
echo json_encode(['error'=>'No files found for upload.']);
// or you can throw an exception
return; // terminate
}
// get the files posted
$images = $_FILES['filer42'];
// a flag to see if everything is ok
$success = null;
// file paths to store
$paths= [];
// get file names
$filenames = $images['name'];
// loop and process files
for($i=0; $i < count($filenames); $i++){
$ext = explode('.', basename($filenames[$i]));
$target = "uploads" . DIRECTORY_SEPARATOR . md5(uniqid()) . "." . array_pop($ext);
if(move_uploaded_file($_FILES["filer42"]["tmp_name"][$i], $target)) {
$success = true;
$paths[] = $target;
} else {
$success = false;
break;
}
}
// check and process based on successful status
if ($success === true) {.
$output = [];
$output = ['uploaded' => $paths];
} elseif ($success === false) {
$output = ['error'=>'Error while uploading images. Contact the system administrator'];
// delete any uploaded files
foreach ($paths as $file) {
unlink($file);
}
} else {
$output = ['error'=>'No files were processed.'];
}
// return a json encoded response for plugin to process successfully
echo json_encode($output);
?>
I think field name is the issue. Because you are getting image name with filer42 and upload time, you are using pictures.
Please change
$_FILES["pictures"]["tmp_name"][$i]
to
$_FILES["filer42"]["tmp_name"][$i]
And check now, Hope it will work. Let me know if you still get issue.
The error is not in this script but in the post.
I was using <input id="filer42" name="filer42" type="file">
but it have to be <input id="filer42" name="filer42[]" type="file" multiple>
as the script seems to need an arrey.
It works just fine now.

How to copy the set of files from one folder to another folder using php

I want to copy set of uploaded files from one folder to another folder.From the below code, all the files in one folder is copied.It takes much time. I want to copy only the currently uploaded file to another folder.I have some idea to specify the uploaded files and copy using for loop.But I don't know to implement.I am very new to developing.Please help me.Below is the code.
<?php
// connect to the database
include('connect-db.php');
if (isset($_POST['submit']))
{
// get form data, making sure it is valid
$udate = mysql_real_escape_string(htmlspecialchars($_POST['udate']));
$file_array=($_FILES['file_array']['name']);
// check to make sure both fields are entered
if ($udate == '' || $file_array=='')
{
// generate error message
$error = 'ERROR: Please fill in all required fields!';
// if either field is blank, display the form again
renderForm($udate, $file_array, $error);
}
else
{
$udate = mysql_real_escape_string(htmlspecialchars($_POST['udate']));
if(isset($_FILES['file_array']))
{
$name_arrray=$_FILES['file_array']['name'];
$tmp_name_arrray=$_FILES['file_array']['tmp_name'];
for($i=0;$i <count($tmp_name_arrray); $i++)
{
if(move_uploaded_file($tmp_name_arrray[$i],"test_uploads/".str_replace(' ','',$name_arrray[$i])))
{
// save the data to the database
$j=str_replace(' ','',$name_arrray[$i]);
echo $j;
$udate = mysql_real_escape_string(htmlspecialchars($_POST['udate']));
$provider = mysql_real_escape_string(htmlspecialchars($_POST['provider']));
$existfile=mysql_query("select ubatch_file from batches");
while($existing = mysql_fetch_array( $existfile)) {
if($j==$existing['ubatch_file'])
echo' <script>
function myFunction() {
alert("file already exists");
}
</script>';
}
mysql_query("INSERT IGNORE batches SET udate='$udate', ubatch_file='$j',provider='$provider',privilege='$_SESSION[PRIVILEGE]'")
or die(mysql_error());
echo $name_arrray[$i]."uploaded completed"."<br>";
$src = 'test_uploads';
$dst = 'copy_test_uploads';
$files = glob("test_uploads/*.*");
foreach($files as $file){
$file_to_go = str_replace($src,$dst,$file);
copy($file, $file_to_go);
/* echo "<script type=\"text/javascript\">
alert(\"CSV File has been successfully Uploaded.\");
window.location = \"uploadbatches1.php\"
</script>";*/
}
} else
{
echo "move_uploaded_file function failed for".$name_array[$i]."<br>";
}
}
}
// once saved, redirect back to the view page
header("Location:uploadbatches1.php");
}
}
else
// if the form hasn't been submitted, display the form
{
renderForm('','','');
}
?>
To copy only the uploaded files, there is only a slight change in the coding which I have made. That is instead of using "." from one folder, I passed the array value. So that only the files which are uploaded will be copied to the new folder instead of copying everything which takes long time.Below is the only change made to do:
$files = glob("test_uploads/$name_arrray[$i]");

display the content of a folder

I have the following PHP code to display the content of a directory in my website:
<?php
$conn = ftp_connect("host") or die("Could not connect");
ftp_login($conn,"username","password");
if ($_GET['dir'] != null) {
ftp_chdir($conn, "logs/{$_GET['dir']}");
}
else
{
ftp_chdir($conn, "logs");
}
$files = ftp_nlist($conn,"");
foreach($files as $value) {
echo "{$value}";
}
ftp_close($conn);
?>
This is my webpage
When I click on the subdirectory1 or subdirectory2, I get the content of it (some images). Then when I click on one of the images, I get the content of the root directory of my website.
How can I display only the image when a visitor clicks on it? Note that I don't want to download it or anything - I just want to display it in the browser when a visitor clicks on it.
You need to establish which of the returned items are files and which are directories. For that you are better of using ftp_rawlist as it allows to extract more data. Then create links for each case and so you can process them appropriately. Here's a possible implementation:
$ftpHost = 'hostname';
$ftpUser = 'username';
$ftpPass = 'password';
$startDir = 'logs';
if (isset($_GET['file'])) {
// Get file contents (can also be fetched with cURL)
$contents = file_get_contents("ftp://$ftpUser:$ftpPass#$ftpHost/$startDir/" . urldecode($_GET['file']));
// Get mime type (requires PHP 5.3+)
$finfo = new finfo(FILEINFO_MIME);
$mimeType = $finfo->buffer($contents);
// Set content type header and output file
header("Content-type: $mimeType");
echo $contents;
}
else {
$dir = (isset($_GET['dir'])) ? $_GET['dir'] : '';
$conn = ftp_connect($ftpHost) or die("Could not connect");
ftp_login($conn, $ftpUser, $ftpPass);
// change dir to avoid ftp_rawlist bug for directory names with spaces in them
ftp_chdir($conn, "$startDir/$dir");
// fetch the raw list
$list = ftp_rawlist($conn, '');
foreach ($list as $item) {
if(!empty($item)) {
// Split raw result into pieces
$pieces = preg_split("/[\s]+/", $item, 9);
// Get item name
$name = $pieces[8];
// Skip parent and current dots
if ($name == '.' || $name == '..')
continue;
// Is directory
if ($pieces[0]{0} == 'd') {
echo "<a href='?dir={$dir}/{$name}'><strong>{$name}</strong></a><br />";
}
// Is file
else {
echo "<a href='?file={$dir}/{$name}'>{$name}</a><br />";
}
}
}
ftp_close($conn);
}
You'll need to add a function which checks which type of file we're handling.
If it's a directory show the regular link (the one you're using now) and if it's an image
show a link with the path of the image.
Because $value contains the name of the file you can use end(explode('.',$value)); to find the ext. of the file (php , jpg , gif , png).
Use another condition with the piece of information and you can identify if it's a picture or not.
In order to build the path of the image you'll need to use the $_GET['dir'] variable's value.
For instance:
<a href='<?=$_GET['dir']?>/Flower.gif'>Flower.gif</a>
I hope you got the idea.

Passing uploaded files to another part of the script for onward processing

I have searched the forum but the closest question which is about the control stream did not help or I did not understand so I want to ask a different question.
I have an html form which uploads multiples files to a directory. The upload manager that handles the upload resides in the same script with a different code which I need to pass the file names to for processing.
The problem is that the files get uploaded but they don't get processed by the the other code. I am not sure about the right way to pass the $_FILES['uploadedFile']['tmp_name']) in the adjoining code so the files can be processed with the remaining code. Please find below the script.
More specif explanation:
this script does specifically 2 things. the first part handles file uploads and the second part starting from the italised comment extracts data from the numerous uploaded files. This part has a variable $_infile which is array which is suppose to get the uploaded files. I need to pass the files into this array. so far I struggled and did this: $inFiles = ($_FILES['uploadedFile']['tmp_name']); which is not working. You can see it also in the full code sample below. there is no error but the files are not passed and they are not processed after uploading.
<?php
// This part uploads text files
if (isset($_POST['uploadfiles'])) {
if (isset($_POST['uploadfiles'])) {
$number_of_uploaded_files = 0;
$number_of_moved_files = 0;
$uploaded_files = array();
$upload_directory = dirname(__file__) . '/Uploads/';
for ($i = 0; $i < count($_FILES['uploadedFile']['name']); $i++) {
//$number_of_file_fields++;
if ($_FILES['uploadedFile']['name'][$i] != '') { //check if file field empty or not
$number_of_uploaded_files++;
$uploaded_files[] = $_FILES['uploadedFile']['name'][$i];
//if (is_uploaded_file($_FILES['uploadedFile']['name'])){
if (move_uploaded_file($_FILES['uploadedFile']['tmp_name'][$i], $upload_directory . $_FILES['uploadedFile']['name'][$i])) {
$number_of_moved_files++;
}
}
}
}
echo "Files successfully uploaded . <br/>" ;
echo "Number of files submitted $number_of_uploaded_files . <br/>";
echo "Number of successfully moved files $number_of_moved_files . <br/>";
echo "File Names are <br/>" . implode(',', $uploaded_files);
*/* This is the start of a script to accept the uploaded into another array of it own for* processing.*/
$searchCriteria = array('$GPRMC');
//creating a reference for multiple text files in an array
**$inFiles = ($_FILES['uploadedFile']['tmp_name']);**
$outFile = fopen("outputRMC.txt", "w");
$outFile2 = fopen("outputGGA.txt", "w");
//processing individual files in the array called $inFiles via foreach loop
if (is_array($inFiles)) {
foreach($inFiles as $inFileName) {
$numLines = 1;
//opening the input file
$inFiles = fopen($inFileName,"r");
//This line below initially was used to obtain the the output of each textfile processed.
//dirname($inFileName).basename($inFileName,'.txt').'_out.txt',"w");
//reading the inFile line by line and outputting the line if searchCriteria is met
while(!feof($inFiles)) {
$line = fgets($inFiles);
$lineTokens = explode(',',$line);
if(in_array($lineTokens[0],$searchCriteria)) {
if (fwrite($outFile,$line)===FALSE){
echo "Problem w*riting to file\n";
}
$numLines++;
}
// Defining search criteria for $GPGGA
$lineTokens = explode(',',$line);
$searchCriteria2 = array('$GPGGA');
if(in_array($lineTokens[0],$searchCriteria2)) {
if (fwrite($outFile2,$line)===FALSE){
echo "Problem writing to file\n";
}
}
}
}
echo "<p>For the file ".$inFileName." read ".$numLines;
//close the in files
fclose($_FILES['uploadedFile']['tmp_name']);
fflush($outFile);
fflush($outFile2);
}
fclose($outFile);
fclose($outFile2);
}
?>
Try this upload class instead and see if it helps:
To use it simply Upload::files('/to/this/directory/');
It returns an array of file names that where uploaded. (it may rename the file if it already exists in the upload directory)
class Upload {
public static function file($file, $directory) {
if (!is_dir($directory)) {
if (!#mkdir($directory)) {
throw new Exception('Upload directory does not exists and could not be created');
}
if (!#chmod($directory, 0777)) {
throw new Exception('Could not modify upload directory permissions');
}
}
if ($file['error'] != 0) {
throw new Exception('Error uploading file: '.$file['error']);
}
$file_name = $directory.$file['name'];
$i = 2;
while (file_exists($file_name)) {
$parts = explode('.', $file['name']);
$parts[0] .= '('.$i.')';
$new_file_name = $directory.implode('.', $parts);
if (!file_exists($new_file_name)) {
$file_name = $new_file_name;
}
$i++;
}
if (!#move_uploaded_file($file['tmp_name'], $file_name)) {
throw new Exception('Could not move uploaded file ('.$file['tmp_name'].') to: '.$file_name);
}
if (!#chmod($file_name, 0777)) {
throw new Exception('Could not modify uploaded file ('.$file_name.') permissions');
}
return $file_name;
}
public static function files($directory) {
if (sizeof($_FILES) > 0) {
$uploads = array();
foreach ($_FILES as $file) {
if (!is_uploaded_file($file['tmp_name'])) {
continue;
}
$file_name = static::file($file, $directory);
array_push($uploads, $file_name);
}
return $uploads;
}
return null;
}
}

Categories