using do..while ,continue? - php

<?php
// initial value
$week = 50;
$year = 2001;
$store = array();
do
{
$week++;
$result = "$week/$year";
array_push($store,$result);
if($week == 53){
$week = 0;
$year++;//increment year by 1
}
continue;
}
// End of Loop
while ($result !== "2/2002");
?>
print_r($store);
result want return will be
array("51/2001", "52/2001", "01/2002", "02/2002");
What is my problems by using while using do..while ,continue?

Your arguments to array_push are the wrong way around. Read the manual entry for functions you use. Turn on warnings on your server; running this in codepad showed me the problem immediately. [Edit: You have now quietly fixed that in your question.]
You also have a typo: $i instead of $week.
Finally, you test against "02/2002", but for that month the string will be "2/2002".
Fixed code (live demo):
<?php
// initial value
$week = 50;
$year = 2001;
$store = array();
do
{
$week++;
$result = "$week/$year";
array_push($store, $result);
if($week == 53){
$week = 0;
$year++;//increment year by 1
}
continue;
}
// End of Loop
while ($result !== "2/2002");
?>
In general, I'd recommend against loops like this. As you've discovered, your code is very fragile because you're testing for just one very specific value, and if that value is not precisely correct you get an infinite loop.
Instead, consider comparing $week and $year separately and numerically:
while ($week < 2 && $year <= 2002)
Next time please include in your question the output that you are seeing, as well as the output that you want to see. It'll save us time in reproducing your problem.

I may not be understanding this correctly... If you could explain a bit more that'd help.
Try turning the loop into a function, and turn the while(..) to check the functions variable.
then just call it 4 times to fill your array.

Related

How to run php file for only 10 times a day without cron?

I am new to php so please mind if it easy question. I have a php script, I want it to be executed only 10 times a day and not more than that. I don't want to use cron for this. Is there any way to do this in php only?
Right now I have set a counter which increases by one every time any one runs the script and loop it to 10 times only. if it exceeds it it shows an error message.
function limit_run_times(){
$counter = 1;
$file = 'counter.txt';
if(file_exists($file)){
$counter += file_get_contents($file);
}
file_put_contents($file,$counter);
if($counter > 11 ){
die("limit is exceeded!");
}
}
I want some efficient way to do this so everyday the script is only executed for 10 times and this is applicable for everyday i.e this counter gets refreshed to 0 everyday or is there any other efficient method.
I would rather recommend that you use a database instead - its cleaner and more simple to maintain.
However, it is achievable with file-handling as well. The file will be of format 2019-05-15 1 (separated by tab, \t). Fetch the contents of the file and split the values by explode(). Then do your comparisons and checks, and return values accordingly.
function limit_run_times() {
// Variable declarations
$fileName = 'my_log.txt';
$dailyLimit = 10;
$content = file_get_contents($fileName);
$parts = explode("\t", $content);
$date = $parts[0];
$counter = $parts[1] + 1;
// Check the counter - if its higher than 10 on this date, return false
if ($counter > $dailyLimit && date("Y-m-d") === $date) {
die("Daily executing limit ($dailyLimit) exceeded! Please try again tomorrow.");
}
// We only get here if the count is $dailyLimit or less
// Check if the date is today, if so increment the counter by 1
// Else set the new date and reset the counter to 1 (as it is executed now)
if (date("Y-m-d") !== $date) {
$counter = 1;
$date = date("Y-m-d");
}
file_put_contents($fileName, $date."\t".$counter);
return true;
}

How to read filenames containing a number and only use those with less than or equal to a specified value, also how to make my 'cache' more efficient?

So I've got a couple of questions that I'm hoping someone will be able to help me with.
Firstly, I'm trying to create a page which parses information and organizes it by the hour into a table. At the moment my script parses the information with Simple HTML Dom and creates a text file for each hour called "hour_%time%.txt" (e.g. hour_02.txt, hour_14.txt, hour_22.txt). Each file will contain the parsed information as a table row.
How would I go about only using the files with times earlier than the current hour, so if the current hour was 9am, only files ending with equal to or less than 09 would be used? I was trying to use either explode or preg_match but I couldn't get it to work.
My code at the moment looks like so:
date_default_timezone_set('UTC');
$currentHour = date('H');
$cache_file = 'cache/hour_'.$currentHour.'.txt';
$data = '<tr><td>'.date('H:00').'</td><td>'.$firmato_count.'</td><td>'.$inviato_count.'</td><td>'.$positive_count.'</td><td>'.$negative_count.'</td></tr>';
file_put_contents($cache_file, $data);
echo '<table class="table"><tbody>';
echo '<tr><th>Time</th><th>Firmato</th><th>Inviato</th><th>Positive</th><th>Negative</th></tr>';
$files = glob("cache/hour_*.txt");
foreach($files as $txt){
$hourlyfile = file_get_contents($txt);
echo $hourlyfile;
}
echo '</table></tbody>';
And secondly, I'm fully aware this isn't the best way to do this but I couldn't figure out a better way myself. Can anyone suggest a more efficient way to store the parsed data and access it? Is it possible to use a single file? I did consider appending the same file however as my page will update frequently it ended up adding multiple lines of data for the same hour. Each file contains a string like so:
<tr><td>10:00</td><td>21</td><td>58</td><td>4</td><td>43</td></tr>
Any help is appreciated.
First convert your String of the hour to a number
[PHP]
$currentHour = intval($currentHour);
next compare
if($currentHour <= 9){ // < for less and <= for less and equal
doStuff
}
This only will display the file of the exact hour. Tell me if doesn't work for edit it.
date_default_timezone_set('UTC');
$currentHour = intval(date('H'));
$cache_file = 'cache/hour_'.$currentHour.'.txt';
$data = '<tr><td>'.date('H:00').'</td><td>'.$firmato_count.'</td><td>'.$inviato_count.'</td><td>'.$positive_count.'</td><td>'.$negative_count.'</td></tr>';
file_put_contents($cache_file, $data);
echo '<table class="table"><tbody>';
echo '<tr><th>Time</th><th>Firmato</th><th>Inviato</th><th>Positive</th><th>Negative</th></tr>';
$files = glob("cache/hour_*.txt");
if($currentHour == $currentHour){
foreach($files as $txt){
$hourlyfile = file_get_contents($txt);
echo $hourlyfile;
}
}
echo '</table></tbody>';
I ended up creating a variable called $globSearch and used if/elseif to create a search string based on the current hour. My code now looks like this:
date_default_timezone_set('UTC');
$currentDate = date('d/m/Y');
$currentHour = intval(date('H'));
$cache_file = 'cache/hour_'.$currentHour.'.txt';
$data = '<tr><td>'.date('H:00').'</td><td>'.$firmato_count.'</td><td>'.$inviato_count.'</td><td>'.$positive_count.'</td><td>'.$negative_count.'</td></tr>';
file_put_contents($cache_file, $data);
echo '<table class="table"><tbody>';
echo '<tr><th>Time</th><th>Firmato</th><th>Inviato</th><th>Positive</th><th>Negative</th></tr>';
if ($currentHour <= 9) {
$globSearch = "{cache/hour_[0][0-".$currentHour."].txt}";
} elseif ($currentHour >= 10 && $currentHour <= 19) {
$splitInt = str_split($currentHour);
$globSearch = "{cache/hour_[0][0-9].txt,cache/hour_[1][0-".$splitInt[1]."].txt}";
} elseif ($currentHour >= 20 && $currentHout <= 23) {
$splitInt = str_split($currentHour);
$globSearch = "{cache/hour_[0][0-9].txt,cache/hour_[1][0-9][2-".$splitInt[1]."].txt}";
}
//$files = glob("{cache/hour_[0][0-9].txt,cache/hour_[1][0-3].txt}", GLOB_BRACE);
$files = glob($globSearch, GLOB_BRACE);
foreach ($files as $txt) {
$hourlyfile = file_get_contents($txt);
echo $hourlyfile;
}
echo '</table></tbody>';
Thanks for replying Ruben and COOLGAMETUBE, much appreciated.

do-while in php resulting a non-stop page loading

I want to have a $startdate counting 3 days backward from an input date by user, where those 3 days are not holidays.
So if the input date by user is October 22, the $startdate would be October 17 instead of October 19. Because October 19 and 20 are holidays
$i = 1;
do{
//some code to produce the $startdate
//...
//end
//check if $startdate is holiday or not
$this->db->where('hl_date',$startdate);
$query = $this->db->get('php_ms_holiday');
//if $startdate = holiday, it doesn't count
if($query->result_array()){
}
else{
$i++;
}
}while($i <= 3);
But, with that code I have a non-stop loading on the browser when a $startdate captured inside the if($query->result_array()) statement. And the browser can only returning results when I put something like this code below, inside the if($query->result_array()) statement:
$i = $i + n; //n is a number starting from 1, or
$i++;
but not:
$i = $i; //or
$i = $i + 0;
Why is that?
You just make a DB query which result interprets as TRUE. Maybe I wrong but it seems you are make the same db query in each loop iteration.
So, check your query, for example add specific date for holiday checking.
if($query->result_array()) will always evaluate to true, if your query is correctly formulated. So also if the number of rows returned is 0. This means that you never ever go to the else. You if-statement should check the number of results returned instead; Furthermore, I personally would prefer a normal for-loop:
for($i = 0; $i < 3)
{
//some code to produce the $startdate
//...
//end
//check if $startdate is holiday or not
$this->db->where('hl_date',$startdate);
$query = $this->db->get('php_ms_holiday');
//if $startdate = holiday, it doesn't count
if [num_rows equals 0] // test num_rows here; Not sure what your class offers here
{
$i++; // increment counter
// do whatever else you want to do
}
}
If this is always true:
if($query->result_array()){
}
Then this will always be true:
}while($i <= 3); //$i is never adjusted, so it will always be less than 3
Since you say that you want to display data from with the last 3 days but if there are holidays in between, you don't want to count them. To get around this I think you should not use the literal "3" since it can be adjusted, it should be a variable too.
A possible solution would be to have a variable such as:
$days_back = 3;
Then try to count the amount of holidays within the last 3 days(or something like that):
//You can make the holidays to be zero by default
$holidays = someWayToCountHolidays($startDate, $endDate); //You'll obviously have to code this
Then you can make make the variable your while loop will work agains
$num_days = $days_back + $holidays; //$holidays can be zero by default
Then something like below for you do while loop:
if($query->result_array()){
//Then do what ever you want to do here
} else {
//Then do what ever you want to do here
}
$i++; //Adjust $i
}while($i <= $num_days);

var_dump changes the result of the function?

I'm on a script which is going to make automatic appointment and the snippet below is for finding an available time. However, I've come across something that i've never heard of before.
When i use var_dump in my script to see the variables(i always do that when coding) the scripts run OK. However, when i remove these lines, script stops working as intended. as i cannot use var_dump for debugging since it makes the script running.
function getfirstfree($length, $limit) {
$length = new DateInterval('PT' . $length . 'M');
$table = "randevu";
$today = date('Y-m-d', time());
$q = $this->db->get_where('randevu', array('date' => $today));
$events = $q->result_array();
if ($q->num_rows() > 0) {
for ($i=0; $i < sizeof($q); $i += 1) {
$c_ends = new DateTime($events[$i]['ends']);
$n_starts = new DateTime($events[$i+1]['starts']);
$freetime = $c_ends->diff($n_starts);
$length_w_break = $length;
$length_w_break->i = $length_w_break->i + 10;
var_dump($length_w_break);
var_dump($freetime);
if ($freetime > $length_w_break) {
echo "ok";
return $c_ends->add(new DateInterval('PT10M'));
}
else {
return "no";
}
}
}
}
without var_dump the scripts returns no. with var_dump, it returns the first free slot.
current values taken from the database is
1-> starts 12:56:09 ends 12:56:09
2-> starts 13:33:11 ends 13:33:11
update var_dump($freetime); changes the output
In current PHP versions, DateInverval object and calculations with DateTime objects cause this bug. Avoid using them and use old-style, calculation with unix-time methods.

I just wrote a horrible PHP function, I need some help (elseif chain - switch?)

I am making a site that determines the value of an array based on what time it is. I wrote this awful (functional) script, and am wondering if I could have made it more concise. I started with a case/switch statement, but had trouble getting multiple conditionals working with it. Here's the dirty deed:
if ($now < november 18th) {
$array_to_use = $home;
}
elseif (november 18th < $now && $now < november 21st ) {
$array_to_use = $driving;
}
elseif (november 21st < $now && $now < november 22nd) {
$array_to_use = $flying;
}
...
...
...
elseif (february 1st < $now) {
$array_to_use = $arrived;
}
else {
$array_to_use = $default;
}
The schedule is actually more complicated and has 13 elseifstatements in it. Can someone please confirm that I just had coder's block and that there's a better way to do this?
EDIT: I changed the Unix Timestamps to rough real times so it's easier to understand what I'm doing (hopefully)
EDIT 2: Please forgive the currently broken Javascript clock, but this is the site I'm working on:
Time Table.
Each array is based on my location, and there are 15 "they are currently" based on the time it is. It's a small problem domain with known start/end times, so flexibility isn't key, just getting it all written. You can see how the time is continuous, and only one array of strings needs to be selected at a time.
First , please please please take out your hardcoded numbers and put them into constants.
$FLIGHT_START_TIME = 1258956001;
$FLIGHT_END_TIME = 1260511201;
Second, I would make mini functions for each of the conditionals:
I.e.
function isFlying($time)
{
return ( $FLIGHT_START_TIME < $time && $time < $FLIGHT_END_TIME );
}
Third, take your whole set of conditionals, and put it into a function to get your current state, and replace in your function calls:
function getStateArrayForTime($time)
{
if (isDriving($time)
{
return $driving;
}
if ( isFlying($time) )
{
return $flying;
}
...etc
}
Last, replace the whole inline section of code with your single function call:
$currentState = getStateArrayForTime($now);
As other posters have also commented, at this point you can use a data table driven function to return the state if you know only the start and end time will be the state parameters:
so replace the implementation of getStateArrayForTime with:
function getStateArrayForTime ($time)
{
//
$states = array (
array("startTime" => 1258956001, "endTime" => 1260511201, "state" => $flying),
array("startTime" => 1260511201, "endTime" => 1260517000, "state" => $driving),
..etc...
);
foreach($states as $checkStateArray)
{
if($checkStateArray['startTime'] < $time && $time < $checkStateArray['endTime'])
{
return $checkStateArray['state'];
}
}
return null;
}
Finally, some people might ask "why do things in this order?" I can't claim credit at all, other than in the application, but Martin Fowler has a great book called "Refactoring" that explains why you clean code up one step at a time, and test at each step of the way, then finally replace functions wholesale that don't make sense, all the while testing that they are functionally equivalent.
It might be overkill, but I would have done something like this so that I could put all the time ranges in one clear spot:
#timeWindows = ({ start -> 0, end -> 1258783201, array -> $home },
... ,
{start -> 1260511201, end -> MAXVAL, array -> $arrived});
and then a loop like
$array_to_use = $default;
foreach (my $window in #timeWindows) {
if (($now > $window->start) && ($now < $window->end)) {
$array_to_use = $window->array;
last;
}
}
Sorry it's in Perl, I don't know PHP, but I imagine it's similar.
You can put the time and array to use in an array and loop them to select.
$Selctions = array(
1258783201 => $Home,
1258956001 => $Driving,
1260511201 => $Flying,
...
1260511201 => $Arriving
);
// MUST SORT so that the checking will not skip
ksort($Selction);
$TimeToUse = -1;
$Now = ...;
foreach ($Selctions as $Time => $Array) {
if ($Now < $Time) {
$TimeToUse = $Time;
break;
}
}
$ArrayToUse = ($TimeToUse != -1) ? $Selctions[$TimeToUse] : $Default;
This method can only be used when the times has no gap (one range right after another).
Hope this helps.
You can use a switch statement, doing something like this:
switch (true)
{
case $now < 1258783201:
// your stuff
break;
case $now < 1258783201
// more of your stuff
break;
//...
}
That's at least a little cleaner...
Something like this:
$array_to_use = null;
$dispatch = array(1258783201, $home, 1258956001, $driving, ..., $arrived);
for ($i=0; i<count($dispatch); $i+=2) {
if ($now<$dispatch[$i]) {
$array_to_use = $dispatch[$i+1];
break;
}
}
if ($array_to_use==null) $array_to_use = $dispatch[count($dispatch)-1];
You also need to think about whether you need "<" or "<=" condition.
You might want to learn the Command Pattern; it can also help in this circumstance.

Categories