Getting abnormal error in Page View Counter using PHP - 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.

Related

how to put jpgraph into PDF using dompdf-0.5.1

It took me 12 hours still no improvement. I try displaying different images from my computer stored in the server and the result was successful. however when displaying the reports pie graph, it wont read every time the system tries to convert to pdf. It gives a blank pdf file. On the other hand, I can view the pie graph I created by using echo''; in the reports.php. I used the same concept in dompdf file but its not working.
DOMPDF
<html>
<head>
<title></title>
</head>
<body>
<?php echo'<img src="reports-display.php"/>';?>
</body>
</html>
<?php
$html = ob_get_clean();
$dompdf = new DOMPDF();
$dompdf->load_html($html);
$dompdf->render();
$dompdf->stream("sample.pdf");
?>
JPGRAPH Drawing
<?php
require('dbcon.php');
require_once('jpgraph/src/jpgraph.php');
require_once ('jpgraph/src/jpgraph_pie.php');
require_once ('jpgraph/src/jpgraph_pie3d.php');
//LEGEND
//YELLOW=LIVE BLUE=WAITING GREEN=DONE
//sql query for live
$live = mysql_query("Select count(*) as count1 from tbl_display_ads where status LIKE '%Live%'") or die(mysql_error());
//sql query for waiting
$waiting = mysql_query("Select count(*) as count2 from tbl_display_ads where status LIKE '%Waiting%'") or die(mysql_error());
//sql query for done/posted advertisement
$done = mysql_query("Select count(*) as count3 from tbl_display_ads where status LIKE '%Done%'") or die(mysql_error());
//While loop for live
while($resultlive = mysql_fetch_array($live))
{
$totallive = $resultlive['count1'];
}
//While loop for waiting
while($resultwaiting = mysql_fetch_array($waiting))
{
$totalwaiting = $resultwaiting['count2'];
}
//While loop for done
while($resultdone = mysql_fetch_array($done))
{
$totaldone = $resultdone['count3'];
}
// Some data
$data = array($totallive,$totalwaiting,$totaldone);
// Create the Pie Graph.
$graph = new PieGraph(500,450);
$theme_class= new VividTheme;
$graph->SetTheme($theme_class);
// Set A title for the plot
$graph->title->Set("Figure 1.1: Totality of Display Advertisement");
// Create
$p1 = new PiePlot3D($data);
$p1->SetCenter(0.5,0.55);
$p1->SetLegends(array("Live","Waiting","Done"));
$graph->legend->SetPos(0.5,0.100,'center','bottom');
$graph->Add($p1);
$p1->ShowBorder();
$p1->SetColor('black');
$p1->ExplodeSlice(1);
$graph->Stroke();
// Get the handler to prevent the library from sending the
// image to the browser
$gdImgHandler = $graph->Stroke(_IMG_HANDLER);
// Stroke image to a file and browser
// Default is PNG so use ".png" as suffix
$fileName = "/tmp/imagefile.png";
$graph->img->Stream($fileName);
// Send it back to browser
$graph->img->Headers();
$graph->img->Stream();
?>
I finally found out the solution. in the report-display.php I set the extension name of the graph to .png and save to the directory folder for reports.
DEFINE("DEFAULT_GFORMAT","auto");
$graph->img->SetImgFormat("png");
if(file_exists("Reports/reports-display.png")) unlink("Reports/reports-display.png");
$graph->Stroke("Reports/reports-display.png");
The problem is that you're essentially asking dompdf to grab an image file called "reports-display.php" from the local filesystem. When you use $dompdf->load_html() dompdf has no idea where the content arrives from. Any resource references in the HTML that lack a full URL are pulled in via the local filesystem. Since dompdf does not parse the PHP the source will be read in, which is obviously not a valid image document.
You're found a valid solution in saving the file locally. There are two other possibilities:
1) Point to the jpgraph script through your web server.
<html>
<head>
<title></title>
</head>
<body>
<img src="http://example.com/reports-display.php"/>
</body>
</html>
2) Capture the jpgraph output and insert into the document as a data-uri.
<html>
<head>
<title></title>
</head>
<body>
<img src="data:image/png;base64,<?php echo base64_encode(include_once('reports-display.php');?>"/>
</body>
</html>
With this method reports-deplay.php would have to be updated to return the image rather than stream it. Something like:
$graph = new PieGraph(500,450);
// snip steps that generate the content
return $graph->Stroke();

fpassthru acting weird (sending the page html rather then the file I want)

I'm really really new to PHP, so if you can explain it to me what my code is actually doing and why the result is what it is I would appreciate very much. I'm probably screwing up something very simple.
Basically I want to query a MySQL database, create a csv with the data, and download the csv. Pretty simple. Here is my code:
<?php
include("Includes/PHPheader.php");
$query_string = $_SERVER['QUERY_STRING'];
parse_str($query_string);
$sql = "SELECT many_columns_i_removed_from_this_sample_code FROM table WHERE id = '".$id."'";
$result = $conn->query($sql);
$row = $result->fetch_assoc();
$f = fopen("csv/tmp.csv", "w");
fputcsv($f, array_keys($row),';');
fputcsv($f,$row,';');
rewind($f);
header('Content-Type: application/csv');
header('Content-Disposition: attachment; filename="tmp.csv"');
fpassthru($f);
fclose($f);
?>
There are some HTML code below it that shouldn't affect anything, but just in case here it is.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title></title>
</head>
<body>
</body>
</html>
Well, I thought this would download my csv with no problem. If I go to the csv folder, there it is, the tmp.csv file I created, with the proper header and data.
But when I open the tmp.csv file I downloaded, it is actually the html code of the page, and not the data I expected.
What is going on?
In case it helps, I'm using WebMatrix 3.0.
There are two things going on, probably. First, You are trying to read (fpassthru) from a file opened for writing (fopen(..., "w")), so You are not able to read anything from the file. Then, after that "reading nothing" goes Your HTML code, which naturally appends to Your output. Try this:
$f = fopen("csv/tmp.csv", "w+");
...
fclose($f);
exit;
Could you please try?
header("Content-type: application/vnd.ms-excel");
instead of
header('Content-Type: application/csv');
I have a test code of CSV output, have a look - https://foowms.googlecode.com/svn/trunk/stockincsv.php
A very informative thread of Stack Overflow
Setting mime type for excel document
==============================================
If csv file open, write and save, then you should do as follows-
$list = array ("Peter,Griffin,Oslo,Norway");
$file = fopen("csv/tmp.csv","w");
foreach ($list as $line) {
fputcsv($file,explode(',',$line));
}
fclose($file);
==============================================
You also could try this
fputcsv($fp, array_values($list), ';', ' ');
instead of
fputcsv($f, array_keys($row),';');

PHP Simple HTML DOM Parser Long loading website

i am working on one project and i have a problem with one thing.
Webpage that i am going to screen scrape have a ~5-10 sec loading time because of high amount of data.
When i am trying screen scrape with PHP Simple HTML DOM Parser i got no results.
Screen is blank. All elements i use is ok, because when i enter another page from the same website which has exactly the same code in the few start lines everything is working.
Is there any chance to wait for website finish loading and then screen scrape.
Thanks
My code is:
<!DOCTYPE html>
<html>
<head>
<title>Test</title>
</head>
<body>
<?php
error_reporting(0);
include_once('../../simple_html_dom.php');
function scraping_slashdot() {
// create HTML DOM
$html = file_get_html('http://www.examplepage.com/');
// get article block
foreach($html->find('div[id="rightBlock"]') as $article) {
// get title1
$item['title1'] = $article->find('div.[class="inputHead"]', 0)->plaintext;
$ret[] = $item;
}
// clean up memory
$html->clear();
unset($html);
return $ret;
}
// -----------------------------------------------------------------------------
//output
$ret = scraping_slashdot();
foreach($ret as $v) {
echo $v['title1'];
}
?>
</body>
</html>
have you tried using jquery? you can complete a function once the page has loaded by adding:
$(document).ready()

Prevent php code from executing in textarea on save

I have an issue with a cms where code inside a textarea is executing when you try to save it. For example, lets say you have a textarea with the following html/php in it.
<div class="footer">
<?php include("assets/footer.php"); ?>
</div>
On most servers it works fine and just reads the code as text and saves it perfectly. However, on other servers, it actually parses the php and executes it when you click save. This causes an error and breaks the app. I have tried different methods of opening and reading the file such as fread and file_get_contents and all seem to behave the same. I also tried to wrap the data loaded into the block as CDATA but that did not help either.
Any other ideas what might be causing this and any way around this?
Thank you VERY much in advance for any help on the subject.
This is how the text is saved:
$fp = #fopen($fname, "w");
if ($fp) {
fwrite($fp, $block);
fclose($fp);
}
This is how the file is read:
if (file_exists($fname)) {
$fp = #fopen($fname, "r");
if (filesize($fname) !== 0) {
$loadblock = fread($fp, filesize($fname));
$loadblock = htmlspecialchars($loadblock);
fclose($fp);
}
}
Here is the form:
<form method = "post" action = "">
<textarea name = "text" ><?php echo $loadblock; ?></textarea>
</form>
Simple ways:
1) Adding & Stripping Slashes
$loadblock = addslashes($_POST['page']);
$loadblock = stripslashes($loadblock);
2) HTML Entities
$loadblock = htmlentities($loadblock);
Those are two simple ways you can do it, this is just so you can understand a basic way or two. :)

PHP Error deleting file

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.

Categories