PHP Error deleting file - php

Error deleting file if there are multiple connections to multiple page.
Error:Warning: unlink(folder/1.txt.txt) [function.unlink]: Permission denied in C:\htdocs\fopen.php on line 7
Note: If only one connection to access everything normally occurs (no error occurs).
PHP code fopen.php:
<?php
function fastWrite($a){
echo 'Coping file: "',$a,'" to "',$a,'.txt"<br>';
copy($a,$a.'.txt');
echo 'Delete file: "',$a,'.txt"<br>';
unlink($a.'.txt');
}
for($i=0;$i<10;$i++){
fastWrite('folder/1.txt');
echo '<hr>';
}
?>
html/javascript code (to simulate multiple connections):
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=iso-8859-1">
<title>my test</title>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
<script type="text/javascript">
function myTest(z){
$.ajax("fopen.php?time="+(new Date().getTime()),{"success":function(data){
$("<div></div>").addClass("sty").html(data).appendTo("body");
},"error":function(a,b,c){
$("<div></div>").addClass("sty").html([a,b,c]).appendTo("body");
}});
}
</script>
<style>
.sty{
border:1px #000 solid;
overflow:auto;
margin:5px 0 0 5px;
}
</style>
</head>
<body>
<p>New test</p>
<script type="text/javascript">
var dd = "";
for(var i=0;i<10;i++){
dd += "myTest(\"#a"+(i+1)+"\");\n";
}
eval(dd);
</script>
</body>
</html>
What did I do wrong?
Thanks.
Solution: clearstatcache

You're having a problem because two processes are trying to copy and delete the same file at the same time. Because they are separate processes, you can't easily control the order in which they do things.
Imagine two processes, running fastWrite() at the same time:
t1 copies 'a' to 'a.txt'
t2 copies 'a' to 'a.txt'
t2 deletes 'a.txt'
t1 tries to delete 'a.txt', but fails because it does not exist
This is called a "race condition".
If you don't mind that the unlink call will sometimes fail, you can ignore the error by using the '#' symbol in front of the command:
#unlink("$a.txt");
I'm pretty sure that saving user-generated data into the same file over and over again isn't your ultimate goal. You obviously encountered this problem in the pursuit of something larger. Maybe you should start a new question more focused on that problem.
If you just need a temporary file to work with during the connection, don't always name the file the same. Instead, you could:
function doStuffToFile($fname) {
$tempName = $fname . "." . getmypid() . "." . rand();
copy($fname, $tempName);
// do stuff to your temporary file
unlink($tempName);
}

The problem is that you have two or more scripts that write to and delete 1.txt.txt. This is called a race condition. Script1.php has no direct way of knowing if Script2.php is using a file, you need to implement this mechanism yourself.
A simple solution is to create a lock file before using the shared file and delete the lock file once you are done with it.
There is a new problem then: how do you ensure that the two scripts do not create the lock file at once? Script1.php might find that lock file isn't there but before it actually creates the file, the processor switches to Script2.php which also finds the lock file missing. What then?
PHP provides a useful flock function. I am not aware of the gory details but I believe it should solve your problem, to some extent, on some platforms at least.
<?php
function fastWrite($a)
{
# //// LOCK \\\\
$fp = fopen("fastwrite.lock", "w");
if (flock($fp, LOCK_EX) === false) { # PHP will stop at this line until the lock is acquired
die("flock failed");
}
# \\\\ LOCK ////
echo 'Coping file: "', $a, '" to "', $a, '.txt"<br>';
copy($a, $a . '.txt');
echo 'Delete file: "', $a, '.txt"<br>';
unlink($a . '.txt');
# //// UNLOCK \\\\
if (flock($fp, LOCK_UN) === false) {
die("flock failed");
}
fclose($fp);
# \\\\ UNLOCK ////
}
for ($i = 0; $i < 10; $i++) {
fastWrite('1.txt');
echo '<hr>';
}
PS: I was not able to reproduce the race condition on my system.

Related

Replace text inside xml tag with PHP

I've been searching far and wide, but couldn't find exactly what I needed, so here I am.
I have a php script that uploads an xml file - no issue here.
With the uploaded file, I need to open it and replace text inside the tags.
Example below
<Styles>
<Style p3:ID="Default" p3:Name="Normal" xmlns:p3="urn:schemas-microsoft-com:office:spreadsheet">
<p3:Font p3:FontName="Arial" p3:Size="10" />
<p3:Alignment p3:Vertical="Top" p3:WrapText="1" />
</Style>
<Style p3:ID="Percent" p3:Name="Percent" xmlns:p3="urn:schemas-microsoft-com:office:spreadsheet">
<p3:NumberFormat p3:Format="0%" />
</Style>
</Styles>
Anywhere you see p2 or p3 I need to replace these with a different syntax ss.
I have php 7.3 installed which broke compatibility with a script I was using (https://pear.php.net/package/File_SearchReplace/redirected) which is no longer maintained unfortunately. Does anyone know either how to update this script or how to achieve the same result using simpleXML maybe?
Many thanks!
You can try this solution. Algorithm for reading a file line by line and working with a string type. You can change the search pattern or method.
Maybe this will help
<?php
// faster replace word in file
function replaceWordInnerFile($pathToFile, $needleRegEx, $replace = null)
{
if (!\is_file($pathToFile)) {
throw new ErrorException('File not found');
}
if (!\is_writable($pathToFile)) {
throw new ErrorException('File not writable');
}
$newFilePath = $pathToFile.'_new';
$fileStream = \fopen($pathToFile, 'r');
$newFileStream = \fopen($pathToFile.'_new', 'w'); # create new file
while ($row = \fgets($fileStream)) {
// use any pattern for search
if (!$replace) {
// empty case
\fwrite($newFileStream, \preg_replace("/\<p[0-9]+:NumberFormat p3:Format=\"${needleRegEx}\"\s+\/\>/", '', $row));
continue;
}
\fwrite($newFileStream, \preg_replace("/\<p([0-9]+):NumberFormat p3:Format=\"${needleRegEx}\"\s+\/\>/", '<p${1}:NumberFormat p3:Format="'.$replace.'">', $row));
}
\fclose($fileStream);
\fclose($newFileStream);
\rename($pathToFile, $pathToFile.'.bak'); // backup original content
\rename($newFilePath, $pathToFile);
}
replaceWordInnerFile('/tmp/file-name', '[0-9]+\%', '669977');
Result
<Styles>
<Style p3:ID="Default" p3:Name="Normal" xmlns:p3="urn:schemas-microsoft-com:office:spreadsheet">
<p3:Font p3:FontName="Arial" p3:Size="10" />
<p3:Alignment p3:Vertical="Top" p3:WrapText="1" />
</Style>
<Style p3:ID="Percent" p3:Name="Percent" xmlns:p3="urn:schemas-microsoft-com:office:spreadsheet">
<p3:NumberFormat p3:Format="669977">
</Style>
</Styles>
Docs:
https://www.php.net/manual/en/function.fopen.php
https://www.php.net/manual/en/function.fputs.php
https://www.php.net/manual/en/function.fgets.php
https://www.php.net/manual/en/function.rename
https://www.php.net/manual/en/function.unlink
https://www.php.net/manual/en/function.preg-replace - Example #1

Getting abnormal error in Page View Counter using PHP

I have page view counter script which fwrite in a .txt file and I echo it in another file where I have to display the page views. The counter updating script is:
$handle = fopen("counter.txt", "r");
if(!$handle){
echo "could not open the file" ;
} else {
$counter = (int ) fread($handle,20);
fclose ($handle);
$counter++;
$handle = fopen("counter.txt", "w" );
fwrite($handle,$counter) ;
fclose ($handle) ;
}
The above code writes (fwrite) page views in file name counter.txt
And the page where I want to show page views is also a combination of HTML and PHP. The code I have added there is following which read views and displays it
$handle = fopen("counter.txt", "r");
if(!$handle){
echo "could not open the file" ;
} else {
$counter = ( int ) fread ($handle,20) ;
}
echo $counter;
The above code shows the page views. It reads from the counter.txt file and displays page views.
I am getting abnormal error for this. When I am trying to access the file via desktop it shows wrong page view. It adds extra 1 view. for e.g. if there is only 1 page view it shows 2
But on android or ios devices it is working fine. For android or ios devices it showing correct count. I want to know is there any problem with the code? In short above script is showing +1 (extra 1 view) every time. (only for laptops or pc's)
<?php
// page-count.php - to be included in other files
class hitcounter{
private $file;
private static $instance=false;
private function __construct($file){
$this->file=$file;
}
public static function initialise( $file ){
if( !self::$instance ) self::$instance=new self( $file );
return self::$instance;
}
public function write(){
$i=$this->read();
$i++;
file_put_contents($this->file,$i,LOCK_EX);
}
public function read(){
return file_exists($this->file) ? (int)file_get_contents($this->file) : 0;
}
public function display(){
printf('<p>Page hits: %s</p>Filename: %s',$this->read(),$this->file);
}
}
$file=sprintf('counter-%s.txt',ip2long($_SERVER['REMOTE_ADDR']));
$oHit=hitcounter::initialise( $file );
?>
The page that will update the textfile
<?php
require 'page-count.php';
# log the page view to the text file
$oHit->write();
?>
<!DOCTYPE html>
<html lang='en'>
<head>
<meta charset='utf-8' />
<title>Update & display hitcount</title>
</head>
<body>
<h1>Update & View PageView count</h1>
<a href='view-page-count.php'>View counter</a> | <a href='javascript:location.reload(true)'>Reload</a>
<?php
# display the hit count
$oHit->display();
?>
</body>
</html>
The page that will view the results only ( view-page-count.php )
<?php
require 'page-count.php';
// do NOT log this page view - only display the count
?>
<!DOCTYPE html>
<html lang='en'>
<head>
<meta charset='utf-8' />
<title>Display hitcount</title>
</head>
<body>
<a href='javascript:history.go(-1)'>Previous Page</a>
<h1>This page only VIEWS logfile - it does NOT update it.</h1>
<?php
$oHit->display();
?>
</body>
</html>
As stated by others, doing a counter with a simple file in PHP is not a good idea. There are many hits on a webpage you are not aware of (e.g. search-engines, known and unknown spiders, normal visitors, ...). These may or may not interfere and want access to this file at the same time. This results in unclear situations which may result in weird errors. Therefore the foremost hint is to use a database which is able to lock the data during access and makes it safe to add the data.
Lets look into your code:
One of the biggest problem is, that writing your file means the OS clears the file and rewrites it. In the worst case it means a harddisc starts, positiones itself at the file, tries to open it, clears it, writes data to it and closes it afterwards. This will take many cycles - enough time to get interrupted by others who try to visit your page as well. Sure a SSD works much faster but not in terms of data-collisions.
If you cannot use a Database we need to try to "lock" your file for single-usage. Here is your updated code:
$handle = fopen("counter.txt", "r");
if(!$handle){
echo "could not open the file" ;
} else {
$counter = (int ) fread($handle,20);
fclose ($handle);
$counter++;
$handle = fopen("counter.txt", "w" );
if (flock($handle, LOCK_EX | LOCK_NB)) {
fwrite($handle, $counter) ;
flock($handle, LOCK_UN); // open the lock again
}
fclose ($handle) ;
}
This tries to lock your file. If it is not lockable it will not block the further execution but pass the fwrite-line. You can remove the LOCK_NB but this means your server will wait till the block is liftet and this may take a while. Blocking a webserver is not a good idea so maybe not counting a visitor is the better way.
A third - a bit more complex - way is to write unique files for visitors in a directory and an automatic collector (e.g. cron-job) of the votes who has a single access to your visitor-file. This way you get no collisions.
Happy coding.

PHP Include giving weird results [duplicate]

This question already has answers here:
How to avoid echoing character 65279 in php?
(12 answers)
Closed 6 years ago.
I see this character in Firebug .
I don't know why this is happening, there's no such character in my code. For Firefox it's OK, but in IE everything breaks. I can't even search for this character in Google.
I saved my file with utf-8 encoding without bom.
The character in question &#65279 is the Unicode Character 'ZERO WIDTH NO-BREAK SPACE' (U+FEFF). It may be that you copied it into your code via a copy/paste without realizing it. The fact that it's not visible makes it hard to tell if you're using an editor that displays actual unicode characters.
One option is to open the file in a very basic text editor that doesn't understand unicode, or one that understands it but has the ability to display any non-ascii characters using their actual codes.
Once you locate it, you can delete the small block of text around it and retype that text manually.
Just use notepad ++ with encoding UTF-8 without BOM.
yeah, its so simple to fix that, just open that file by notepad++ and step follow --> Encoding\ encoding UTF-8 without BOM.
then save that.
It work for me as well!
Try:
<?php
// Tell me the root folder path.
// You can also try this one
// $HOME = $_SERVER["DOCUMENT_ROOT"];
// Or this
// dirname(__FILE__)
$HOME = dirname(__FILE__);
// Is this a Windows host ? If it is, change this line to $WIN = 1;
$WIN = 0;
// That's all I need
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>UTF8 BOM FINDER and REMOVER</title>
<style>
body { font-size: 10px; font-family: Arial, Helvetica, sans-serif; background: #FFF; color: #000; }
.FOUND { color: #F30; font-size: 14px; font-weight: bold; }
</style>
</head>
<body>
<?php
$BOMBED = array();
RecursiveFolder($HOME);
echo '<h2>These files had UTF8 BOM, but i cleaned them:</h2><p class="FOUND">';
foreach ($BOMBED as $utf) { echo $utf ."<br />\n"; }
echo '</p>';
// Recursive finder
function RecursiveFolder($sHOME) {
global $BOMBED, $WIN;
$win32 = ($WIN == 1) ? "\\" : "/";
$folder = dir($sHOME);
$foundfolders = array();
while ($file = $folder->read()) {
if($file != "." and $file != "..") {
if(filetype($sHOME . $win32 . $file) == "dir"){
$foundfolders[count($foundfolders)] = $sHOME . $win32 . $file;
} else {
$content = file_get_contents($sHOME . $win32 . $file);
$BOM = SearchBOM($content);
if ($BOM) {
$BOMBED[count($BOMBED)] = $sHOME . $win32 . $file;
// Remove first three chars from the file
$content = substr($content,3);
// Write to file
file_put_contents($sHOME . $win32 . $file, $content);
}
}
}
}
$folder->close();
if(count($foundfolders) > 0) {
foreach ($foundfolders as $folder) {
RecursiveFolder($folder, $win32);
}
}
}
// Searching for BOM in files
function SearchBOM($string) {
if(substr($string,0,3) == pack("CCC",0xef,0xbb,0xbf)) return true;
return false;
}
?>
</body>
</html>
copy this code to php file upload to root and run it.
for more about this: http://forum.virtuemart.net/index.php?topic=98700.0
"I don't know why this is happening"
Well I have just run into a possible cause:-) Your HTML page is being assembled
from separate files. Perhaps you have files which only contain the body or banner portion of your final page. Those files contain a BOM (0xFEFF) marker. Then as part of the merge process you are running HTML tidy or xmllint over the final merged HTML file.
That will cause it!
If you are using Notepad++, "Menu" >> "Encoding" >> "Convert to UTF-8" your "include" files.
If you have a lot of files to review, you can use this tool:
https://www.mannaz.at/codebase/utf-byte-order-mark-bom-remover/
Credits to Maurice
It help me to clean a system, with MVC in CakePhp, as i work in Linux, Windows, with different tools.. in some files my design was break.. so after checkin in Chrome with debug tool find the &#65279 error
Before clear space (trim)
Then replace with RegEx .replace("/\xEF\xBB\xBF/", "")
I'm working on Javascript, I did with JavaScript.
An old stupid trick that works in this case... paste code from your editor to ms notepad, then viceversa, and evil character will disappears !
I take inspiration from wyisyg/msword copypaste problem.
Notepad++ utf-8 w/out BOM works as well.
Here's my 2 cents:
I had the same problem and I tried using Notepad++ to convert to UTF-8 no BOM, and also the old "copy to MS notepad then back again" trick, all to no avail. My problem was solved by making sure all files (and 'included' files) were the same file system; I had some files that were Windows format and some that had been copied off a remote Linux server, so were in UNIX format.

Ajax save function to server doesn't work correctly

I'm working on a website that let's users simply save a note, to be accessed later. I'm however having quite some trouble with actually saving the note. I first had it set to automatically save on each keypress, but it's better if I have the user press on a button to save the file. What you'll also see in the code is that the note gets saved as the users IP address, when the user then visits the site again he'll see the same note (if he has the same IP again).
The error I get now when clicking the save button is:
PHP Warning: file_put_contents() [<a href='function.file-put-contents'>function.file-put-contents</a>]: Filename cannot be empty in /home/martmart/public_html/index.php on line 41
My index.php:
<?php
$note_name = 'note.txt';
$uniqueNotePerIP = true;
if($uniqueNotePerIP){
// Use the user's IP as the name of the note.
// This is useful when you have many people
// using the app simultaneously.
if(isset($_SERVER['HTTP_X_FORWARDED_FOR'])){
$note_name = 'notes/'.$_SERVER['HTTP_X_FORWARDED_FOR'].'.txt';
}
else{
$note_name = 'notes/'.$_SERVER['REMOTE_ADDR'].'.txt';
}
}
if(isset($_SERVER['HTTP_X_REQUESTED_WITH'])){
// This is an AJAX request
if(isset($_POST['note'])){
// Write the file to disk
file_put_contents($note_name, $_POST['note']);
echo '{"saved":1}';
}
exit;
}
$note_content = 'Write something here :D';
if(file_exists($note_name) ){
$note_content = htmlspecialchars( file_get_contents($note_name) );
}
function saveNow() {
// Write the file to disk
file_put_contents($note_name, $_GET['note']);
echo '{"saved":1}';
}
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Marty Testweb</title>
<!-- Our stylesheet -->
<link rel="stylesheet" href="assets/css/styles.css" />
<!-- A custom google handwriting font -->
<link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Courgette" />
<!--[if lt IE 9]>
<script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<script src="assets/audiojs/audio.min.js"></script>
<script>
audiojs.events.ready(function() {
var as = audiojs.createAll();
});
</script>
</head>
<body>
<div id="pad">
<h2>Note</h2>
<textarea id="note"><?php echo $note_content ?></textarea>
</div>
<!-- Initialise scripts. -->
<script>
function saveNow()
{
alert("<?php saveNow(); ?>");
}
</script>
<button id="save" onclick="saveNow()">Save Note</button>
<!-- JavaScript includes. -->
<script src="http://code.jquery.com/jquery-latest.min.js"></script>
<script type="text/javascript" src="assets/js/script.js"></script>
</body>
<div id="footer">
<footer>
<a href="">
<div id="footer_right">
Version 0.1.2
</div id="footer_right">
</a>
<audio src="assets/audiojs/music.mp3" preload="auto"></audio>
<div id="footer_left">
Save function not working yet
</div id="footer_left">
</footer>
</div id="footer">
</html>
The script.js:
$(function(){
var note = $('#note');
var saveTimer,
lineHeight = parseInt(note.css('line-height')),
minHeight = parseInt(note.css('min-height')),
lastHeight = minHeight,
newHeight = 0,
newLines = 0;
var countLinesRegex = new RegExp('\n','g');
// The input event is triggered on key press-es,
// cut/paste and even on undo/redo.
note.on('input',function(e){
// Count the number of new lines
newLines = note.val().match(countLinesRegex);
if(!newLines){
newLines = [];
}
// Increase the height of the note (if needed)
newHeight = Math.max((newLines.length + 1)*lineHeight, minHeight);
// This will increase/decrease the height only once per change
if(newHeight != lastHeight){
note.height(newHeight);
lastHeight = newHeight;
}
}).trigger('input'); // This line will resize the note on page load
function ajaxSaveNote(){
// Trigger an AJAX POST request to save the note
$.post('index.php', { 'note' : note.val() });
}
});
I don't really know how to solve this, so any help is greatly appreciated. I just want to have the file save with the same name as the user's IP address, when he click on the button. Please keep in mind I'm still a big newbie with these more advanced features so please point out anything I did wrong (but also please explain it easy :) ).
Thanks for reading,
Mart.
First of all I would suggest considering whether having the filename be the IP address is a good idea...many workplaces and other group settings share the same IP address, so any user at a workplace like that would see the note left by any other user at the same workplace.
As to your error, I think the problem may be that you didn't declare $note_name as a global variable within your function. Try changing it to this:
function saveNow() {
global $note_name;
// Write the file to disk
file_put_contents($note_name, $_GET['note']);
echo '{"saved":1}';
}
In PHP if you want to use a global variable (one that wasn't declared inside a function or class) within a function, you always have to use the global keyword as shown above. Using global variables can be avoided entirely if you structure your code a bit differently, but that's another topic.
I wonder why you didn't get a notice about it not being defined though...while you're still developing you might want to put this at the top of your code:
error_reporting(E_ALL);
P.S. Although your code will work without doing this, for security reasons it would be good to specify the JSON MIME type before outputting JSON from PHP, e.g.:
function saveNow() {
global $note_name;
// Write the file to disk
file_put_contents($note_name, $_GET['note']);
header('Content-type: application/json');
echo '{"saved":1}';
exit;
}

prevent some parts of html from showing in code retrieved from remote page using curl

I am retreiving source code from remote page using curl then echo it in my page using echo $html but this echo the whole remote page . what i am tring to do is to prebvent some parts
from being echod in my page (the ads that are in the remote pageand some other parts) the remote page code is almost like that
<IFRAME FRAMEBORDER=0 MARGINWIDTH=0 MARGINHEIGHT=0 SCROLLING=NO WIDTH=728 HEIGHT=90 SRC="http://creative.xtendmedia.com/proxy/matomymediaproxy.html?ad_type=ad&ad_size=728x90&section=2650714"></IFRAME>
<script type="text/javascript" src="http://www.youradexchange.com/script/java.php?option=rotateur&rotateur=83132"></script>
<script language="JavaScript"> var zflag_nid="1723"; var zflag_cid="18"; var zflag_sid="0"; var zflag_width="1"; var zflag_height="1"; var zflag_sz="15"; </script>
<script language="JavaScript" src="http://c1.zxxds.net/jsc/c1/fo.js"></script>
i currently use preg_match_all('#(<iframe.*myspecificword.*/iframe>)#i', $html, $matches);
var_dump($matches);
but its not effective as the the specfic word differs every time .
is there is any other better ways provided that the part of the code i want do display only is always the line no 59 ? how can echo this line only?
You need something similar to Python Beautiful Soup, but for PHP, like this. Anyway, it is probably using a regex under the hood, so it might not be faster than your solution. Certainly, it's cleaner.
EDIT: I discourage this, but if you know that you script will be always line 59 of the file and a single line only, then read it line by line discarding the first 58, like this:
$stream = fopen('http://php.net/manual/en/function.fopen.php', 'r');
if (!$stream) {
// Report error
}
for ($i = 0; $i < 58; $i++) {
fgets($stream);
}
// Here is line 59
$myline = fgets($stream);
echo $myline;
You might have to expand the recognized line terminators list with:
ini_set('auto_detect_line_endings',true);
Instead, if the page is a string, then use explode() to break it at line terminators and then select the 59th element of the returned array.

Categories