Renaming file with PHP - php

I am using code that i found on here which works great but the moment i try to access a file in a sub-directory it just doesn't want to work.
It gets a file, creates a temp file to write to, then looks for some text in the file and replaces that text with new text, then saves the updated file, then deletes the temp file.
The below works fine:
$reading = fopen('links.htm', 'r');
$writing = fopen('links.tmp', 'w+');
$replaced = false;
while (!feof($reading)) {
$line = fgets($reading);
if (stristr($line,'::template::')) {
$line = "replacement line!\n";
$replaced = true;
}
fputs($writing, $line);
}
fclose($reading); fclose($writing);
// might as well not overwrite the file if we didn't replace anything
if ($replaced)
{
rename('links.tmp', 'links.htm');
} else {
unlink('links.tmp');
}
This doesnt work:
$reading = fopen('path/to/links.htm', 'r');
$writing = fopen('path/to/links.tmp', 'w+');
$replaced = false;
while (!feof($reading)) {
$line = fgets($reading);
if (stristr($line,'::template::')) {
$line = "replacement line!\n";
$replaced = true;
}
fputs($writing, $line);
}
fclose($reading); fclose($writing);
// might as well not overwrite the file if we didn't replace anything
if ($replaced)
{
rename('path/to/links.tmp', 'path/to/links.htm');
} else {
unlink('path/to/links.tmp');
}
Any suggestions?
The path is absolute i defined it in the code earlier and use it to create file and write files to but when i want the code above to work in the same way it just doesn't want to.
Also the folders permissions has been set to write and read which also works fine.
Ran the code in the sub folder and works fine but not from the top level directory.
Error reporting is turned off, turned it on now:
The process cannot access the file because it is being used by another process. (code: 32)

So after a week of looking around, testing, breaking and recoding a lot i found a simple way to do this.
Since most of the content is dynamically created as well as the links.htm file, it was quite hard finding where and when the file is accessed since the code accesses about 300 of my clients sites and updates the links file.
Simple fix:
$path = "path/on/server/";
$conn_id = ftp_connect("ftp.testftp.com") or die("Could not connect");
ftp_login($conn_id,"admin","ert456");
$old_file = $path.'links.htm';
$new_file = $path.'_template.htm';
ftp_rename($conn_id, $old_file, $new_file);
$source = fopen($new_file, "w");
$localTarget = "path/to/links.htm";
ftp_fget($conn,$source,$localTarget,FTP_ASCII);
$reading = fopen('path/to/links.htm', 'r');
$writing = fopen('path/to/_template.htm', 'w+');
$replaced = false;
while (!feof($reading)) {
$line = fgets($reading);
if (stristr($line,'::template::')) {
$line = "replacement line!\n";
$replaced = true;
}
fputs($writing, $line);
}
fclose($reading); fclose($writing);
// might as well not overwrite the file if we didn't replace anything
if ($replaced)
{
rename('path/to/_template.htm', 'path/to/links.htm');
} else {
unlink('path/to/_template.htm');
}
$local_file = "path/to/links.htm";
ftp_put($conn_id, $path, $local_file, FTP_BINARY);
ftp_close($conn_id);
There is probably easier ways to do this but this is what worked for me, hope it helps someone.

PHP will need to have write permissions to that directory in order to write to it. It may be that it has write permissions to the current directory ., but does not have permissions to write to the subdirectory ./path/to/.
Edit: If you get a PHP error, you should include it in your question.
Edit after OP Edit:
That error means that something currently has links.htm opened. I see that you're fclose()ing the file before renaming it, so my guess is that you probably have links.htm open in some other application (e.g. browser or text editor).
Edit #3:
If you do not have one of the links.htm or links.tmp files open in another application, it could be that you're using Windows - in which case the rename() call will execute before the fclose() even though it comes after it in the code. The solution to this is to add a sleep() call after closing the handle:
fclose($reading); fclose($writing);
sleep(1); // this should allow the handle to be properly closed before the rename() call

Related

simple php page session visit counter not working

I am having this strange issue and can't figure it out.
On some websites I have this script works perfect... same code, same server settings...
With php, there is a simple page view hit counter that stores locally in a txt file.
Then I echo out the value on the footer copyright area of my websites to give the client a quick statistic... its pretty cool how fast it grows.
Anyway.. i have a client corner grill ny . com (seo purposes I added spaces )
On that website.. its been working great for years.
Now another website and a bunch more.. for example... savianos . com
This breaks.. and the text value is blank.
This is the counter.php code
<?php
session_start();
$counter_name = "counter/hits.txt";
//Check if a text file exists. If not create one and initialize it to zero.
if (!file_exists($counter_name)) {
$f = fopen($counter_name, "w");
fwrite($f,"0");
fclose($f);
}
// Read the current value of our counter file
$f = fopen($counter_name,"r");
$counterVal = fread($f, filesize($counter_name));
fclose($f);
// Has visitor been counted in this session?
// If not, increase counter value by one
if(!isset($_SESSION['hasVisited'])){
$_SESSION['hasVisited']="yes";
$counterVal++;
$f = fopen($counter_name, "w");
fwrite($f, $counterVal);
fclose($f);
}
?>
Now, if I add a value in the txt file.. like 1040... and go to the website it starts to work... then after a week or so I check it .. its blank again.
Any ideas?
I am thinking that this may be happening because the website might get a TON of views during dinner time friday night.. and the simple script can't handle it so.. while its trying to write a added a number it just breaks and go to blank.. and never starts back up again.
The structure is this.
/counter/ folder has
counter.php and a hits.txt file
Every page of the website the very first thing is
<?php include ('counter/counter.php'); ?>
and in the footer of the website we have
<?php echo $counterVal; ?>
Your code looks perfect, but let's understand the situation. You have a file which can be accessed concurrently for many users, because page visit can be done by multiple users on same time. This does't seem right you have to lock the file manipulation for another user while someone is modifying it, right?. Please have a look
Visits counter without database with PHP
It is most likely because you have two concurrent scripts that tried to open the file at one and one of them fail. You have to use flock() when there are multiple instances of the script that could operate at the same time. Counter are some of the heaviest things if you going to use file reading and writing. I wrote this wrapper to easily implement file locking.
If you want to check out one of my counters that in operation try http://ozlu.org. That dynamic counter image was self-built. The fileReadAll will read the entire file in one shot. The file writer only has two modes, write or append. You can pass the fileWriter an array or a string and it will write it to the file. The function will not add any \n to format your text so you would have to add that. The default mode for the fileWriteAll is w if you do not set the third argument.
function fileWriteAll($file, $content, $mode = "w"){
$mode = $mode === "w" || $mode === "a"? $mode : "w";
$FILE = fopen($file, $mode);
while (!flock($FILE, LOCK_EX)) { usleep(1); }
if( is_array($content) ){
for ($i = 0; $i < count($content); $i++){
fwrite($FILE, $content[$i]);
}
} else {
fwrite($FILE, $content);
}
flock($FILE, LOCK_UN);
fclose($FILE);
}
function fileReadAll($file){
$FILE = fopen($file, 'r');
while (!flock($FILE, LOCK_SH)) { usleep(1); }
$content = fread($FILE, filesize($file));
flock($FILE, LOCK_UN);
fclose($FILE);
return $content;
}
Your modified code:
session_start();
$counterName = './views.txt';
if (!file_exists($counterName)) {
$file = fopen($counterName, 'w');
fwrite($file, '0');
fclose($file);
}
$file = fopen($counterName, 'r');
$value = fread($file, filesize($counterName));
fclose($file);
if (! isset($_SESSION['visited'])) {
$_SESSION['visited'] = 'yes';
$value++;
$file = fopen($counterName, 'w');
fwrite($file, $value);
fclose($file);
}
session_unset();
echo $value;

My php script won't open files that aren't in its root directory

This is a php script for a user login system that I am developing.
I need it to read from, and write to, the /students/students.txt file, but it won't even read the content already contained in the file.
<?php
//other code
echo "...";
setcookie("Student", $SID, time()+43200, "/");
fopen("/students/students.txt", "r");
$content = fread("/students/students.txt", filesize("/students/students.txt"));
echo $content;
fclose("/students/students.txt");
fopen("/students/students.txt", "w");
fwrite("/students/students.txt", $content."\n".$SID);
fclose("/students/students.txt");
//other code
?>
You are not using fopen() properly. The function returns a handle that you then use to read or edit the file, for example:
//reading a file
if ($handle = fopen("/students/students.txt", "r"))
{
echo "info obtained:<br>";
while (($buffer = fgets($handle))!==false)
{ echo $buffer;}
fclose($handle);
}
//writing/overwriting a file
if ($handle = fopen("/students/students.txt", "w"))
{
fwrite($handle, "hello/n");
fclose($handle);
}
Let me know if that worked for you.
P.S.: Ty to the commentators for the constructive feedback.
There are many ways to read/write to file as others have demonstrated. I just want to illustrate the mistake in your particular approach.
fread takes a file handle as param, NOT a string that represents the path to the file.
So your line:
$content = fread("/students/students.txt", filesize("/students/students.txt")); is incorrect.
It should be:
$file_handle = fopen("/students/students.txt", "r");
$content = fread($file_handle, filesize("/students/students.txt"));
Same thing when you write contents to file using fwrite. Its reference to the file is a File Handle opened using fopen NOT the filepath. when opening a file using fopen() you can also check if the $file_handle returned is a valid resource or is false. If false, it means the fopen operation was not successful.
So your code:
fopen("/students/students.txt", "w");
fwrite("/students/students.txt", $content."\n".$SID);
fclose("/students/students.txt");
Needs to be re-written as:
$file_handle = fopen("/students/students.txt", "w");
fwrite($file_handle, $content."\n".$SID);
fclose($file_handle);
You can see that fclose operates on file handles as well.
File Handle (as per php.net):
A file system pointer resource that is typically created using fopen().
Here are a couple of diagnostic functions that allow you to validate that a file exists and is readable. If it is a permission issue, it gives you the name of the user that needs permission.
function PrintMessage($text, $success = true)
{
print "$text";
if ($success)
print " [<font color=\"green\">Success</font>]<br />\n";
else
print(" [<font color=\"red\">Failure</font>]<br />\n");
}
function CheckReadable($filename)
{
if (realpath($filename) != "")
$filename = realpath($filename);
if (!file_exists($filename))
{
PrintMessage("'$filename' is missing or inaccessible by '" . get_current_user() . "'", false);
return false;
}
elseif (!is_readable($filename))
{
PrintMessage("'$filename' found but is not readable by '" . get_current_user() . "'", false);
return false;
}
else
PrintMessage("'$filename' found and is readable by '" . get_current_user() . "'", true);
return true;
}
I've re-written your code with (IMO) a cleaner and more efficient code:
<?php
$SID = "SOMETHING MYSTERIOUS";
setcookie("Student", $SID, time()+43200, "/");
$file = "/students/students.txt"; //is the full path correct?
$content = file_get_contents($file); //$content now contains /students/students.txt
$size = filesize($file); //do you still need this ?
echo $content;
file_put_contents($file, "\n".$SID, FILE_APPEND); //do you have write permissions ?
file_get_contents
file_get_contents() is the preferred way to read the contents of a
file into a string. It will use memory mapping techniques if supported
by your OS to enhance performance.
file_put_contents
This function is identical to calling fopen(), fwrite() and
fclose() successively to write data to a file. If filename does not
exist, the file is created. Otherwise, the existing file is
overwritten, unless the FILE_APPEND flag is set.
Notes:
Make sure the full path /students/students.txt is
correct.
Check if you've read/write permissions on /students/students.txt
Learn more about linux file/folder permissions or, if you don't access to the shell, how to change file or directory permissions via ftp
Try to do this:
fopen("students/students.txt", "r");
And check to permissions read the file.

php program cannot change the values of text file

I'm making a unique visitors counter for my website and I went for many tutorials, until I found this easy code but the problem is that the program never adds new ips or counts new visits . The values of ip.txt and count.txt never change :(
Here is the whole code :
<?php
function hit_count() {
$ip_address = $_SERVER ['REMOTE_ADDR'];
$ip_file = file ('ip.txt');
foreach($ip_file as $ip) {
$ip_single = ($ip);
if ($ip_address==$ip_single){
$found = true;
break;
} else {
$found = false;
}
}
if ($found==true){
$filename = 'count.txt';
$handle = fopen ($filename, 'r');
$current = fread($handle, filesize($filename));
fclose($handle);
$current_inc = $current = 1;
$handle = fopen($filename, 'w');
fwrite($handle, $current_inc);
fclose($handle);
$handle = fopen('ip.txt', 'a');
fwrite($handle, $ip_address."\n");
fclose($handle);
}
}
?>
This code is full of mistakes. It will never work.
Mistake number #1:
$ip_file = file('ip.txt');
Each element on $ip_file ends with a newline symbol, so even if your IP is in the list it will never match $_SERVER ['REMOTE_ADDR']. file() must be run with the FILE_IGNORE_NEW_LINES flag.
Mistake number #2:
if ($found==true){
The counter will only increase and try to add the IP in the list if it was already found in the list. If the list is empty it will never do jack. Invert this logic!
Mistake number #3:
$current_inc = $current = 1;
It will never count beyond 1.
Besides that, you must make sure that the PHP script has permission to change those files. Usually the scripts don't have permission to edit the site files for security reasons.
All that said, your script should be changed to something more like this:
if (!in_array($_SERVER['REMOTE_ADDR'], file('ip.txt', FILE_IGNORE_NEW_LINES)))
{
file_put_contents('ip.txt', $_SERVER['REMOTE_ADDR'] . "\n", FILE_APPEND);
$count = file_get_contents('count.txt');
$count++;
file_put_contents('count.txt', $count);
}
Clean, simple, direct. But you still have to make sure the PHP script has permission to edit those files.

PHP not writing to file from one source

I have an issue I can't seem to find the solution for. I am trying to write to a flat text file. I have echoed all variables out on the screen, verified permissions for the user (www-data) and just for grins set everything in the whole folder to 777 - all to no avail. Worst part is I can call on the same function from another file and it writes. I can't see to find the common thread here.....
function ReplaceAreaInFile($AreaStart, $AreaEnd, $File, $ReplaceWith){
$FileContents = GetFileAsString($File);
$Section = GetAreaFromFile($AreaStart, $AreaEnd, $FileContents, TRUE);
if(isset($Section)){
$SectionTop = $AreaStart."\n";
$SectionTop .= $ReplaceWith;
$NewContents = str_replace($Section, $SectionTop, $FileContents);
if (!$Handle = fopen($File, 'w')) {
return "Cannot open file ($File)";
exit;
}/*
if(!flock($Handle, LOCK_EX | LOCK_NB)) {
echo 'Unable to obtain file lock';
exit(-1);
}*/
if (fwrite($Handle, $NewContents) === FALSE) {
return "Cannot write to file ($File)";
exit;
}else{
return $NewContents;
}
}else{
return "<p align=\"center\">There was an issue saving your settings. Please try again. If the issue persists contact your provider.</p>";
}
}
Try with...
$Handle = fopen($File, 'w');
if ($Handle === false) {
die("Cannot open file ($File)");
}
$written = fwrite($Handle, $NewContents);
if ($written === false) {
die("Invalid arguments - could not write to file ($File)");
}
if ((strlen($NewContents) > 0) && ($written < strlen($NewContents))) {
die("There was a problem writing to $File - $written chars written");
}
fclose($Handle);
echo "Wrote $written bytes to $File\n"; // or log to a file
return $NewContents;
and also check for any problems in the error log. There should be something, assuming you've enabled error logging.
You need to check for number of characters written since in PHP fwrite behaves like this:
After having problems with fwrite() returning 0 in cases where one
would fully expect a return value of false, I took a look at the
source code for php's fwrite() itself. The function will only return
false if you pass in invalid arguments. Any other error, just as a
broken pipe or closed connection, will result in a return value of
less than strlen($string), in most cases 0.
Also, note that you might be writing to a file, but to a different file that you're expecting to write. Absolute paths might help with tracking this.
The final solution I ended up using for this:
function ReplaceAreaInFile($AreaStart, $AreaEnd, $File, $ReplaceWith){
$FileContents = GetFileAsString($File);
$Section = GetAreaFromFile($AreaStart, $AreaEnd, $FileContents, TRUE);
if(isset($Section)){
$SectionTop = $AreaStart."\n";
$SectionTop .= $ReplaceWith;
$NewContents = str_replace($Section, $SectionTop, $FileContents);
return $NewContents;
}else{
return "<p align=\"center\">There was an issue saving your settings.</p>";
}
}
function WriteNewConfigToFile($File2WriteName, $ContentsForFile){
file_put_contents($File2WriteName, $ContentsForFile, LOCK_EX);
}
I did end up using absolute file paths and had to check the permissions on the files. I had to make sure the www-data user in Apache was able to write to the files and was also the user running the script.

PHP's fopen is terminally failing

Okay, I have GOT to be missing something totally rudimentary here.
I have an extremely simple use of PHP's fopen function, but for some reason, it will not open the file no matter what I do.
The odd part about this is that I use fopen in another function in the same script and it's working perfectly. I'm using the fclose in both functions. So, I know it's not a matter of a rogue file handle.
I have confirmed the file's path and the existence of the target file also.
I'm running the script at the command-line as root, so I know it's not apache that's the cause. And since I am running the script as root, I am fairly confident that permissions are not the issue.
So, what on earth am I missing here?
function get_file_list() {
$file = '/home/site/tmp/return_files_list.txt';
$fp = fopen($file, 'r') or die("Could not open file: /home/site/tmp/return_files_list.txt for reading.\n");
$files_list = array();
while($line = fgets($fp)) {
$files_list[] = $line;
}
fclose($fp);
return $files_list;
}
function num_records_in_file($filename) {
$fp = fopen( $filename, 'r' ); # or die("Could not open file: $filename\n");
$counter = 0;
if ($fp) {
while (!feof( $fp )) {
$line = fgets( $fp );
$arr = explode( '|', $line );
if (( ( $arr[0] != 'HDR' && $arr[0] != 'TRL' ) && $arr[0] != '' )) {
++$counter;
continue;
}
}
}
fclose( $fp );
return $counter;
}
As requested, here's both functions. The second function is passed an absolute path to the file. That is what I used to confirm that the file is there and that the path is correct.
Wow! Well, I figured it out.
On a whim, I decided to try trimming the file name. Apparently, it was carrying some whitespace or something at the end of the filename. So, when it tried to open the file, it couldn't due to looking for $filename +
Learn something new everyday, I guess.

Categories