I've been struggling with writing a single string into a file.
I'm using just a simple code under Slackware 13:
$fp = fopen('/my/absolute/path/data.txt', 'w');
fwrite($fp, 'just a testing string...');
fclose($fp);
The file gets created (if it's not already created) but it's empty ?!
The directory in which this file is written is owned by apache's user & group (daemon.daemon) and has 0777 permissions.
This has never happened to me before. I'm curious what's the reason I'm not able to write inside the file ?
Thanks in advance.
Try $ df -h
It probably means your disk is full.
In my opinion you could check the return values:
$fp = fopen('/my/absolute/path/data.txt', 'w');
// $fp -> manual: "Returns a file pointer resource on success, or FALSE on error."
if ($fp) {
$bytes_written = fwrite($fp, 'just a testing string...');
if ($bytes_written) {
echo "$bytes_written bytes written!\n";
} else {
echo "Error while writing!\n"
}
$success = fclose($fp);
if ($success) {
echo "File successfully closed!\n";
} else {
echo "Error on closing!\n";
}
} else {
echo "No filepointer ressource!\n";
}
I suggest using file_put_conents($file_name, $file_cotents);
And to retrieve content: file_get_contents($file_name);
Code looks cleaner too.
http://php.net/manual/en/function.file-put-contents.php and
http://www.php.net/manual/en/function.file-get-contents.php
Could be something is happening to the script/file before the file is closed. Check if there are any other processes that try to access the file (you can use lsof). Also try writing to a new file to see if the same thing occurs.
Also, check the return value on fclose() to make sure the file is being closed successfully.
Related
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.
I wonder, why PHP file_put_contents() function works in a weird way.
I used it in a loop to write some logs to file and all was fine (new lines were appended even if no flag was specified). When I started the script again, it re-created my file.
From PHP doc:
If filename does not exist, the file is created. Otherwise, the
existing file is overwritten, unless the FILE_APPEND flag is set.
OK, so my question is: Why (when used in one loop) it doesn't overwrite my file (without FILE_APPEND flag of course)? Bug or feature? :)
Edit: Example context of use when this happened:
$logFile = dirname ( __FILE__ ) . '/example.log';
foreach($something1 as $sth1) {
$logData .= "Something\n";
foreach($something2 as $sth2) {
if($something_else) {
$logData .= "Line: \t" . $sth2 . "\n";
file_put_contents($logFile, $logData);
}
}
}
As it has been very clearly mentioned in this link under the flags content(which you should have read) it clearly states that if file filename already exists, append the data to the file instead of overwriting it(when this flag is set). So when the flag for FILE_APPEND is set it appends and when not it rewrites. Hope this helped you.
Alternative Way
<?php
$file = 'file.txt';
$append = true;
if (file_exists($file)) {
if ($append) {
// append file
$file = fopen($file, 'a+');
} else {
// overwrite file
$file = fopen($file, 'a');
}
} else {
// create file
$file = fopen($file, 'a');
}
fwrite($file, 'text');
fclose($file);
?>
here is a php fopen documentation
and php file
and read on its related topics
ok, when you are run the script each time try to rename the log file with random number or currentdate timestamp and try to save it in your DB
by this when you again run the script and can take the log file name from DB and update it when you needed
My telecom vendor is sending me a report each time a message goes out. I have written a very simple PHP script that receive values via HTTP GET. Using fwrite I write the query parameter to a CSV file.The filename is report.csv with the current date as a prefix.
Here is the code :
<?php
error_reporting(E_ALL ^ E_NOTICE);
date_default_timezone_set('America/New_York');
//setting a the CSV File
$fileDate = date("m-d-Y") ;
$filename = $fileDate."_Report.csv";
$directory = "./csv_archive/";
//Creating handle
$handle = fopen($filename, "a");
//These are the main data field
$item1 = $_GET['item1'];
$item2 = $_GET['item2'];
$item3 = $_GET['item3'];
$mydate = date("Y-m-d H:i:s") ;
$pass = $_GET['pass'];
//testing the pass
if (isset($_GET['pass']) AND $_GET['pass'] == "password")
{
echo 'Login successful';
// just making sure the function could write to it
if (!$handle = fopen($directory.$filename, 'a')){
echo "Cannot open file ($filename)";
exit;
}
//writing the data I receive through query string
if (fwrite($handle, "$item1,$item2,$item3,$mydate \n") === FALSE) {
echo "Cannot write to file ($filename)";
exit;
}
fclose($handle);
}
else{
echo 'Login Failure please add the right pass to URL';
}
?>
The script does what I want, but the only problem is inconsistency, meaning that a good portion of the records are missing (about half the report). When I log to my account I can get the complete report.
I have no clue of what I need to do to fix this, please advice.
I have a couple of suggestions for this script.
To address Andrew Rhyne's suggestion, change your code that reads from each $GET variable to:
$item1 = (isset($_GET['item1']) && $_GET['item1']) ? $_GET['item1'] : 'empty';
This will tell you if all your fields are being populated.
I suspect you problem is something else. It sounds like you are getting a seperate request for each record that you want to save. Perhaps some of these requests are happening to close together and are messing up each other's ability to open and write to the file. To check if this is happening, you might try using the following code check if you opened the file correctly. (Note that your first use of 'fopen' in your script does nothing, because you are overwriting $handle with your second use of 'fopen', it is also opening the wrong file...)
if (!$handle = fopen($directory.$filename, 'a')){
$handle = fopen($directory.date("Y-m-d H:i:s:u").'_Record_Error.txt', 'a');
exit;
}
This will make sure that you don't ever lose data because of concurrent write attempts. If you find that this is indeed you issue, you can delay subsequent write attempts until the file is not busy.
$tries = 0;
while ($tries < 50 && !$handle = fopen($directory.$filename, 'a')){
sleep(.5);//wait half a second
$tries++;
}
if($handle){
flock($handle);//lock the file to prevent other requests from opening the file until you are done.
} else {
$handle = fopen($directory.date("Y-m-d H:i:s:u").'_Record_Error.txt', 'a');//the 'u' is for milliseconds
exit;
}
This will spend 25 seconds, trying to open the file once every half second and will still output your record to a unique file every time you are still unable to open the file to write to. You can then safely fwrite() and fclose() $handle as you were.
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.
How can one retrieve a varibale for instance alias /MyDirectory/ "C:/MyDirectory/MyDirectory/" from http.conf using PHP. Is there an easier way than to open http.conf and read it line by line?
Thanks
You could always use fgets() to read single lines from a file. But why would you want to tinker with your server settings from your program?
$handle = fopen('httpd.conf', 'r');
if($handle) {
while($buffer = fgets($handle) !== false) {
// do something with the data you read
}
if (!feof($handle)) {
echo 'An error occured';
}
fclose($handle);
}