Concurrent File Writes PHP - php

I have a project with a paranoid client... He is worried the site is going to crash if more than 200 people are using the site at the same time.
Does my script look like it will collect the data okay? Or will the file give users errors?
<?php
if($_POST['name'] && $_POST['email']) {
//file name var
$fileName = "mycsvfile.csv";
//grab from form
$name = $_POST['name'];
$email = $_POST['email'];
//date
date_default_timezone_set("America/Los_Angeles");
$today = date("F j, Y, g:i a");
//set the data we need into an array
$list = array (
array($today, $name, $email)
);
// waiting until file will be locked for writing (1000 milliseconds as timeout)
if ($fp = fopen($fileName, 'a')) {
$startTime = microtime();
do {
$canWrite = flock($fp, LOCK_EX);
// If lock not obtained sleep for 0 - 100 milliseconds, to avoid collision and CPU load
if(!$canWrite) usleep(round(rand(0, 100)*1000));
} while ((!$canWrite)and((microtime()-$startTime) < 1000));
//file was locked so now we can store information
if ($canWrite) {
foreach ($list as $fields) {
fputcsv($fp, $fields);
}
}
fclose($fp);
}
//Send them somewhere...
header( 'Location: http://alandfarfaraway' ) ;
}else{
echo "There was an error with your name and email address.";
}
?>

Use a database such as MySQL to store your data. It will handle a much higher load.
http://php.net/manual/en/book.mysql.php

Related

How to display a different message read from a file every day of the week in php?

I have a php function that reads a line (random message) from a file and displays it on my web page. It displays a new message every time I click refresh, but I want it to display the message for a day (it should change at midnight). Is it possible to do it with another function, implying my database? Or with a JS function?
EDIT
This is the function (not my code):
function loadMessagesFromFile()
{
$path = ROOT_PATH. '/messages.txt';
$file = fopen($path,"r");
$messages = array();
while($data = fgets($file))
{
$messages[] = $data;
}
fclose($file);
return $messages;
}
This is how I use it to display the message:
$messages_from_file = loadMessagesFromFile();
$key = array_rand($messages_from_file);
$full_text = $messages_from_file[$key];
LATER EDIT
I found the answer here: <https://stackoverflow.com/questions/6815614/generating-word-of-the-day-via-php-random-number#:~:text=Just%20set%20the%20current%20date,same%20number%20for%20one%20Day.>
You have multiple possibilities:
Create a file with only one line every day taken from the other file
Create a cron who will be executed ad midnight who will get a random message and set it in database or cache.
If you want a different message per people but persist one day, you can use the local storage of the visitor to store the message with the current date and if the date stored is different from the current date, you change it.
get total lines from your file
Use a database or file and store a random number daily.
Use that number to read a random message from the file.
Use cron to update random numbers at midnight in your database or file.
So, for 24 hours the same message will be displayed.
function getRandomNo(): int {
$path = ROOT_PATH. '/randomno.txt';
$file = fopen($path,"r");
$data = fread($file,100);
fclose($file);
if($data) {
$parts = explode('=',$data);
if($parts[0] != date("Y-m-d")) {
$randomNo = rand(0,100);
overWrite($randomNo);
} else {
$randomNo = $parts[1];
}
} else {
$randomNo = rand(0,100);
overWrite($randomNo);
}
return $randomNo;
}
function overWrite(int $randomNo): void {
$path = ROOT_PATH. '/randomno.txt';
$file = fopen($path,"w+");
$data = date("Y-m-d").'='.$randomNo;
fwrite($file, $data);
fclose($file);
}
$messages_from_file = loadMessagesFromFile();
$key = getRandomNo();
$full_text = $messages_from_file[$key];

Chat message displays in opposite order

I am developing a website where users can type message in a div.
This is the format of the message which will be saved in the file post_archieve.php.
The problem is that the most recent message is on the bottom, and the oldest message is on the top of the div which is the opposite of what I intended.
How can I get the messages to appear in the correct order?
$handle = fopen("post_archieve.php", "a") or die("error"); //deschid cu a ca sa pastreze continutul
$mesaj = $_POST['message'];
$timestamp = time()+ 60*60;
$Time = gmdate("d-m-Y H:i:s", $timestamp);
$postare = '<p class="paragraf">'.$Time."<br>".$username."\r\n"." : ".$mesaj.'</p>';
fwrite($handle, $postare);
fclose($handle);
Append mode adds what you write to the end of the file. If you want to insert at the beginning, you need to read the entire file into a variable, concatenate that to the new data, and rewrite the file.
$mesaj = $_POST['message'];
$timestamp = time()+ 60*60;
$Time = gmdate("d-m-Y H:i:s", $timestamp);
$postare = '<p class="paragraf">'.$Time."<br>".$username."\r\n"." : ".$mesaj.'</p>';
$contents = file_get_contents("post_archieve.php");
$contents = $postare . $contents;
file_put_contents("post_archieve.php", $contents);
Note also that your code is wide open to Cross-Site Scripting attacks. You should encode the message with:
$mesaj = htmlspecialchars($_POST['message']);

PHP How to generate new file txt per day with data

I've created data collection for a specific txt file. I need the script to separate records per days.
For example: today is 100 data and i need have a log16Jan.txt file, tomorrow we have 52 data and i need have a log17Jan.txt file?
How i can do that?
<?php
$name = $_POST['name'];
$tekst = "Name: $namee \r\n";
$uchwyt = fopen("log.txt", "a");
fwrite($uchwyt, $tekst);
fclose($uchwyt);
header("Location: http://#/complete.html");
?>
You can get the date using the date() function and add it to the file name, like this:
$name = $_POST['name'];
$tekst = "Name: $name \r\n";
// Adding today's date to the log file
$uchwyt = fopen("log".date("dM").".txt", "a");
fwrite($uchwyt, $tekst);
fclose($uchwyt);
header("Location: http://#/complete.html");
You could use the date() function.
And since you are creating log files you should consider using a log file name that will sort natively in date order in a directory listing. This will make it easier to find a specific log file in a large listing of files. It will also give you more log file cleanup/removal options.
For example:
// 2018-01-16-log.txt
$logFilename = date("Y-m-d") . "-log.txt";
$uchwyt = fopen($logFilename, "a");
UPDATE: per your request about adding a line number before each log line, there are many ways to do this and some depend on your server environment (Linux/Windows). You could read each line from the log and keep a counter. Or you could use a server utility, like Linux wc (Word Count). Here's one way to do it:
<?php
// 2018-01-16-log.txt
$logFilename = date("Y-m-d") . ".log";
echo "Log file = $logFilename\n";
if (! file_exists($logFilename)) {
$count = 0;
} else {
// use Linux wc utility
$count = system("wc -l < $logFilename");
$count = trim($count);
}
echo "Lines = '$count'\n";
$name = $_POST['name'];
if (! $name) {
$name = "NONE";
}
$tekst = "$count. Name: $name \n";
$uchwyt = fopen($logFilename, "a");
fwrite($uchwyt, $tekst);
fclose($uchwyt);
?>

Automatically create cache file with php

I have been using a basic caching system on my site based on this link
It has so far worked well for everthing I want to do.
$cachefile = 'cache/'. basename($_SERVER['QUERY_STRING']) . '.html';
$cachetime = 1440 * 60;
if (file_exists($cachefile) && (time() - $cachetime < filemtime($cachefile))) {
include($cachefile);
echo "<!-- Cached ".date('jS F Y H:i', filemtime($cachefile))." -->";
exit;
}
ob_start();
// My html/php code here
$fp = fopen($cachefile, 'w'); // open the cache file for writing
fwrite($fp, ob_get_contents()); // save the contents of output buffer to the file
fclose($fp); // close
ob_end_flush(); // Send to browser
However I have a couple of pages with more detailed mysql queries, I have spent a fair bit of time optimising it however it still takes about 10 secs to run when I query it in mysql and even longer on the website. And sometimes it seems to time out as I get the below message.
The proxy server received an invalid response from an upstream server.
The proxy server could not handle the requestGET http://www.example.com
Reason: Error reading from remote server
This isn't a huge issue as because I am using the caching system above only the first person to click on it for the day gets the delay and the rest of the time the users get the cached page so it is actually quite fast for them.
I want to save myself from having to be the first person each day to go to the page and automate this process so at 17:00 (on the server) each day the file gets written to the cache.
How would I best achieve this?
I suggest you to use Php Speedy or this may help:
<?php
function getUrl () {
if (!isset($_SERVER['REQUEST_URI'])) {
$url = $_SERVER['REQUEST_URI'];
} else {
$url = $_SERVER['SCRIPT_NAME'];
$url .= (!empty($_SERVER['QUERY_STRING']))? '?' . $_SERVER[ 'QUERY_STRING' ] : '';
}
return $url;
}
//getUrl gets the queried page with query string
function cache ($buffer) { //page's content is $buffer
$url = getUrl();
$filename = md5($url) . '.cache';
$data = time() . '¦' . $buffer;
$filew = fopen("cache/" . $filename, 'w');
fwrite($filew, $data);
fclose($filew);
return $buffer;
}
function display () {
$url = getUrl();
$filename = md5($url) . '.cache';
if (!file_exists("/cache/" . $filename)) {
return false;
}
$filer = fopen("cache/" . $filename, 'r');
$data = fread($filer, filesize("cache/" . $filename));
fclose($filer);
$content = explode('¦', $data, 2);
if (count($content)!= 2 OR !is_numeric($content['0'])) {
return false;
}
if (time()-(100) > $content['0']) { // 100 is the cache time here!!!
return false;
}
echo $content['1'];
die();
}
// Display cache (if any)
display(); // if it is displayed, die function will end the program here.
// if no cache, callback cache
ob_start ('cache');
?>
Just include this script anywhere you need caching and set a cron job for running it automated.

Cache Weather in PHP

My code:
<?
$url = 'http://w1.weather.gov/xml/current_obs/KGJT.xml';
$xml = simplexml_load_file($url);
?>
<?
echo $xml->weather, " ";
echo $xml->temperature_string;
?>
This works great, but I read that caching external data is a must for page speed. How can I cache this for lets say 5 hours?
I looked into ob_start(), is this what I should use?
The ob system is for in-script cacheing. It's not useful for persistent multi invocation caching.
To do this properly, you'd write the resulting xml out of a file. Every time the script runs, you'd check the last updated time on that file. if it's > 5 hours, you fetch/save a fresh copy.
e.g.
$file = 'weather.xml';
if (filemtime($file) < (time() - 5*60*60)) {
$xml = file_get_contents('http://w1.weather.gov/xml/current_obs/KGJT.xml');
file_put_contents($file, $xml);
}
$xml = simplexml_load_file($file);
echo $xml->weather, " ";
echo $xml->temperature_string;
ob_start would not be a great solution. That only applies when you need to modify or flush the output buffer. Your XML returned data is not being sent to the buffer, so no need for those calls.
Here's one solution, which I've used in the past. Does not require MySQL or any database, as data is stored in a flat file.
$last_cache = -1;
$last_cache = #filemtime( 'weather_cache.txt' ); // Get last modified date stamp of file
if ($last_cache == -1){ // If date stamp unattainable, set to the future
$since_last_cache = time() * 9;
} else $since_last_cache = time() - $last_cache; // Measure seconds since cache last set
if ( $since_last_cache >= ( 3600 * 5) ){ // If it's been 5 hours or more since we last cached...
$url = 'http://w1.weather.gov/xml/current_obs/KGJT.xml'; // Pull in the weather
$xml = simplexml_load_file($url);
$weather = $xml->weather . " " . $xml->temperature_string;
$fp = fopen( 'weather_cache.txt', 'a+' ); // Write weather data to cache file
if ($fp){
if (flock($fp, LOCK_EX)) {
ftruncate($fp, 0);
fwrite($fp, "\r\n" . $weather );
flock($fp, LOCK_UN);
}
fclose($fp);
}
}
include_once('weather_cache.txt'); // Include the weather data cache

Categories