PHP: JSON file that refreshes every x hours automatically - php

I make a PHP request that queries a database every time a map coordinate is changed. This returns some JSON data. I'd like to make a request every 5 hours, as the data does not change often. If this is not possible do you recommend generating a static JSON document that refreshes itself every 5 hours? How can I do this?
My actual code for querying the database on every request looks like this:
public function getAgenciesJson() {
if(Request::ajax()) { # Just validation to show/send data if requested
$ne_lat = $_GET['ne_lat'];
$sw_lat = $_GET['sw_lat'];
$ne_lng = $_GET['ne_lng'];
$sw_lng = $_GET['sw_lng'];
$page = (isset($_GET['page'])) ? (int)$_GET['page'] : 1;
$per_page = 2;
if ($page > 1) { # && $page <= $total_pages) {
$skip = ($page - 1) * $per_page;
} else {
// error - show first set of results
$skip = 0;
}
$agencies = DB::table('users')
->select('user_id','type','c_name','c_logo','c_local','state','city','sn','col','lat','lng')
->skip($skip)
->take($per_page) # Results per page
->where('active',1)
->whereNotNull('lat')
->whereNotNull('lng')
->whereRaw('lat < ? AND lat > ? AND lng < ? AND lng > ?',array($ne_lat,$sw_lat,$ne_lng,$sw_lng));
if(isset($_GET['type_l'])==true && isset($_GET['type_a'])==true) {
$agencies
->orWhere('type','l')
->where('type','a');
} elseif (isset($_GET['type_l'])==true) {
$agencies->where('type','l');
} elseif (isset($_GET['type_a'])==true) {
$agencies->where('type','a');
} else {
$agencies
->orWhere('type','l')
->where('type','a');
}
$i=0;
try {
foreach($agencies->get() as $agency) {
# Assign values
$arr[$i]['a_id'] = $agency->user_id;
$arr[$i]['type'] = $agency->type;
$arr[$i]['name'] = $agency->c_name;
$arr[$i]['logo'] = $agency->c_logo;
$arr[$i]['local'] = $agency->c_local;
$arr[$i]['state'] = $agency->state;
$arr[$i]['city'] = $agency->city;
$arr[$i]['address'] = ($agency->col) ? $agency->sn.', '.$agency->col : $agency->sn;
$arr[$i]['latlon'] = array($agency->lng,$agency->lat);#$agency->lat.",".$agency->lng;#
# Reset variables
$i++;
$latlon=NULL;
}
} catch(Exception $e) { $arr[0]['res'] = null; }
$total = $agencies->count();
$meta = array(
"page" => $page,
"per_page" => $per_page,
"count" => $total,
"total_pages"=> ceil($total/$per_page)
);
return Response::json(array('results'=>$arr,'meta'=>$meta));
} else {
App::abort(404);
}
}

Like Kepoly said in comments, cron is solution. If you have access to server and you use Debian/Ubuntu do:
# crontab -e -u <your webserver account, usually www-data>
And type in:
0 00,05,10,15,20 * * * php <path to your script>
This task will run "0th minute of 12am and 5am and 10am and 3pm and 8pm every day".
For other distros there should be similar way
If you don't have access to server you could use webcron service, like this one: http://www.mywebcron.com/

Related

Google cloud task divide into subtasks by firebase data

I have a google task which gets all companies from my firebase database. I then go through each of those companies in a loop and call additional task for updating each specific company. My problem is that my companies count is increasing and when doing foreach like this i can get into memory limit issues. Here is the actual code for calling the tasks and subtasks:
$router->get('companies', function () use ($router) {
$slackDataHelpersService = new \App\Services\SlackDataHelpersService();
$companiesDocuments = $slackDataHelpersService->getCompanies();
foreach ($companiesDocuments->documents() as $document) {
$cid = $document->id();
createTask('companies', 'updateCompany', "{$cid}");
}
return res(200, 'Task done');
});
How can i separate my initial companies documents into chunks and call a task for each of those chunks? For example, a task that will go through every 100 documents instead of the whole list?
Here is what i tried without success(i used members in this case):
$router->get('test2', function () use ($router) {
$db = app('firebase.firestore')->database();
$membersRef = $db->collection('companies')->document('slack-T01L7H2NDPB')->collection('members');
$query = $membersRef->orderBy('created', 'desc')->limit(10);
$perPage = 10;
$batchCount = 10;
$lastCreated = null;
while ($batchCount == $perPage) {
$loopQuery = clone $query;
if ($lastCreated != null) {
$loopQuery->startAfter($lastCreated);
}
$docs = $loopQuery->documents();
$docsRows = $docs->rows();
$batchCount = count($docsRows);
if ($batchCount > 1) {
$lastCreated = $docsRows[$batchCount - 1];
}
echo $lastCreated['created'];
//createTasksByDocs($docs);
}
//return res(200, 'Task done');
});
I ended up making a function which uses a while loop and loops until it reaches the limit:
function paginateCollections($ref, $limit, $functionName)
{
$query = $ref->orderBy('created', 'desc')->limit($limit);
$perPage = $limit;
$batchCount = $limit;
$lastCreated = null;
while ($batchCount == $perPage) {
$loopQuery = clone $query;
if ($lastCreated != null) {
$loopQuery = $loopQuery->startAfter([$lastCreated]);
}
$docs = $loopQuery->documents();
$docsRows = $docs->rows();
$batchCount = count($docsRows);
if ($batchCount > 1) {
$lastCreated = $docsRows[$batchCount - 1]['created'];
}
if (function_exists($functionName)) {
$functionName($docs);
}
}
}

How to rewrite a php script to JavaScript

I have an express server running using nodejs, and I'm using SQL syntax to query data from my MYSQL database.
The query is to get all members under the current user ID and also get members under it's children and so on, to get a genealogy tree. I'm trying to query a genealogy tree for a user.
I have a PHP script for the query, which worked fine
This is the PHP script:
$memory = $_GET['memory'];
echo '<div style="background:#ccc;display:flex;width:50px;height:50px;justify-
content:center;align-items:center;border-radius:50%;">'.$memory.'</div>';
$transend = array($memory);
$step = 1;
for ($i=0; $i < $step; $i++) {
$under = $transend[$i];
$get = $con->query("SELECT * FROM multilevel WHERE `under`='$under'");
$cnt = $get->num_rows;
if ($cnt>0) {
for ($g=0; $g < $cnt; $g++) {
$fet = $get->fetch_object();
$id = $fet->id;
$position = $fet->position;
array_push($transend, $id);
$step = $step*2;
echo '<div style="background:#ccc;display:flex;width:50px;height:50px;justify-content:center;align-items:center;border-radius:50%;">'.$id.'-'.$position.'</div>';
}
} else {
break;
}
}
I am trying to rewrite it using SQL syntax in node. This is my nodejs code:
A Tree Constructor
const Tree = function (binary) {
this.position = binary.position;
this.level = binary.level;
this.user_id = binary.user_id;
this.under_user_id = binary.under_user_id;
this.brought_by = binary.brought_by;
this.username = binary.username;
};
A method to get all binary for a user
Tree.findBinaries = async (id, result) => {
const theId = parseInt(id);
let transend = [theId];
let step = 1;
let data = [];
for (let i = 0; i < step; i++) {
const under = transend[i];
connection.query(
`SELECT * FROM multilevel WHERE under = ?`,
under,
(err, res) => {
if (err) {
result(null, err);
return;
}
if (res.length) {
for (let index = 0; index < res.length; index++) {
const { id } = res[index];
// push id
transend.push(id);
data.push(res[index]);
step = step * 2;
}
result(null, data);
} else {
result(null, "no data found");
}
}
);
}
};
The transend.push(id) and data.push(res[index]), are not been pushed to the top level, also the step is not been updated. So the loop is running just once.
The expected Result is supposed to be 16 items of children and children of children, But it is currently returning to just the first level. I don't know what I'm currently doing wrong.

PHP: How do I check if one UNIX timestamp range overlaps any UNIX timestamp range?

How to check if one UNIX timestamp range is overlapping another UNIX timestamp range in PHP?
I am developing an application which takes future reservations. But, only one (1) reservation is allowed per period.
Example:
Mr. X has a reservation for a resource from 10:00 A.M. to 12:00 P.M. (noon). Later, Ms. Y wants to reserve that same resource from 8:00 A.M. to 11:00 P.M.. My application should reject Ms. Y's attempted reservation because it overlaps Mr. X's prior reservation.
I am storing the start and end times of existing reservations in UNIX timestamps (integers), but I could convert them into the following format "yyyy-mm-dd hh:mm:ss" if required, or vice versa.
I do not understand how to solve this problem. If I check the new start time with all the existing reservation start times, and the new end time in a similar fashion, the logic will have many if statements and make the application slow.
Would you please help me to solve this issue in an efficient way without using lots of server resources.
Your help is greatly appreciated.
Thanks
Introduction
In other words, you need to do a comparison of all reservation intervals (UNIX timestamps) for a particular resource to determine if a new reservation is valid (within the domain for new reservations).
Step 1
First, a SQL query similar to this might help. While key words like ANY, ALL, NOT, EXISTS and others may seem tempting, it is up to you to decide how much information you need in the event of a scheduling conflict (based on your UI). This query provides the opportunity to extract the maximum amount of information (in PHP, etc ...) about a potential reservation with look ahead forecasting.
// A query like this might help. It's not perfect, but you get the idea.
// This query looks for ALL potential conflicts, starting and ending.
$sql = "SELECT DISTINCT `t1`.`startTime`, `t1`.`endTime`
FROM `reservations` AS `t1`
INNER JOIN `resources` AS `t2`
ON `t1`.`resourceId` = `t2`.`resourceId`
WHERE `t2`.`resourceId` = :resourceId
AND (`t1`.`startTime` BETWEEN :minTime1 AND :maxTime1)
OR (`t1`.`endTime` BETWEEN :minTime2 AND :maxTime2)
ORDER BY `t1`.`startTime` ASC";
Potentially. this will leave you with a multi-dimentional array. The following logic allows you to get a report detailing why the reservation cannot be made. It is up to you to interpret the report in another module.
Step 2
Generalize the solution as a methods of a Reservation class. Depending on your RDBMS, you may be able to do something like this in SQL. Although, it will probably be far less specific and you may want that granularity later. You could send the report in JSON format to a JavaScript front end (just something to think about).
private function inOpenDomain(array $exclusion, $testStart, $testEnd)
{
$result = null;
$code = null;
$start = $exclusion[0];
$end = $exclusion[1];
if (($testStart > $end) || ($testEnd < $start)) {
$result = true;
$code = 0; //Good! No conflict.
} elseif ($testStart === $start) {
$result = false;
$code = 1;
} elseif ($testStart === $end) {
$result = false;
$code = 2;
} elseif ($testEnd === $start) {
$result = false;
$code = 3;
} elseif ($testEnd === $end) {
$result = false;
$code = 4;
} elseif (($testStart > $start) && ($testEnd < $end)) { //Middle
$result = false;
$code = 5;
} elseif (($testStart < $start) && ($testEnd > $start)) { //Left limit
$result = false;
$code = 6;
} elseif (($testStart < $end) && ($testEnd > $end)) { //Right limit
$result = false;
$code = 7;
} elseif (($testStart < $start) && ($testEnd > $end)) { //Both limits
$result = false;
$code = 8;
} else {
$result = false;
$code = 9;
}
return ['start' => $start, 'end' => $end, 'result' => $result => 'code' => $code];
}
Step 3
Make a method that manages the checking of prior reservation times (assuming PDO::FETCH_ASSOC).
private function checkPeriods(array $periods, $newStartTime, $newEndTime)
{
$report = [];
if (!isset($periods[0])) { //If NOT multi-dimensional
$report = inOpenDomain($periods, $newStartTime, $newEndTime)
} else {
for ($i = 0, $length = $count($periods); $i < $length; ++$i) {
$report[$i] = inOpenDomain($periods[$i], $newStartTime, $newEndTime);
}
}
return $report;
}
Step 4
Fashion a method for doing a SELECT on the reservations table using a PDO prepared statement. Generally, ...
private function getReservationTimes($resourceId, $minTime, $maxTime)
{
$sql = "SELECT DISTINCT `t1`.`startTime`, `t1`.`endTime`
FROM `reservations` AS `t1`
INNER JOIN `resources` AS `t2`
ON `t1`.`resourceId` = `t2`.`resourceId`
WHERE `t2`.`resourceId` = :resourceId
AND (`t1`.`startTime` BETWEEN :minTime1 AND :maxTime1)
OR (`t1`.`endTime` BETWEEN :minTime2 AND :maxTime2)
ORDER BY `t1`.`startTime` ASC";
$stmt = $this->db->prepare($sql);
$stmt->bindParam(:resourceId , $resourceId);
$stmt->bindParam(:minTime1 , $minTime);
$stmt->bindParam(:maxTime1 , $maxTime);
$stmt->bindParam(:minTime2 , $minTime);
$stmt->bindParam(:maxTime2 , $maxTime);
$stmt->execute();
return $stmt->fetchAll();
}
Step 5
Make a public method (interface) for the entire process.
public function isOpen($minTime, $maxTime)
{
$periods = $this->getReservationTimes($this->resource->getResourceId(), $minTime, $maxTime);
if (empty($periods)) {
return true; //You may reserve the resource during the time period.
}
return $this->checkPeriods($periods, $this->start, $this->end));
}
Step 6
Separate the concerns.
Create a class hierarchy for the actual items being reserved.
abstact class Product
{
}
class Resource extends Product implements Reservable //Or, something ...
{
private $resourceId;
//etc ....
}
Create a class hierarchy for reservations.
abstract class Interval
{
private $start;
private $end;
public function __construct($start, $end)
{
$this->start = $start;
$this->end = $end;
}
}
class Reservation extends Interval
{
private $db;
private $resource;
public function __construct(PDO $pdo, Reservable $resource, $reqStartTime, $reqEndTime)
{
parent::__construct($reqStartTime, $reqEndTime);
$this->db = $pdo;
$this->resource = $resource;
}
}
Step 7
Run within try/catch
When you instantiate the Reservation object, supply at least a Reservable object, the requested start time, and requested end time (as UNIX timestamps, in this case).
try
{
$day = 84600; // Seconds per day.
$future = $day * 90; // Application specific.
//User requested times.
$reqStartTime = 1488394687 + $day; // Tomorrow.
$reqEndTime = 1488394687 + ($day * 2); // Two day duration.
//Search constraints.
$minTime = time(); // Today. Right now.
$maxTime = 1488394687 + $future; // 90 day look ahead.
$reservation = new Reservation($pdo, $resourceObj, $reqStartTime, $reqEndTime);
$availability = $reservation->isOpen($minTime, $maxTime);
if($availability === true){
$reservation->confirm();
} else {
//Have some other object deal with the report
$reporter = new Reporter($availability);
$reporter->analyzeReport();
//Have some other object update the view, etc ...
}
}
catch(Exception $e)
{
//Handle it.
}

Load more feature with json

I am trying to implement a load more feature in a web app I am building.
When the app loads, it makes an ajax call to controller which retrieves the data from the database and then encodes them in JSON.
I am making use of limits and offsets in mysql query and I more data to be loaded as the user scrolls down.
This is the method in the controller which the ajax call is made to
function latest_pheeds($offset = 0) {
//Confirm if a user is logged before allowing access
if($this->isLogged())
{
//Limit
$limit = 20;
//user id
$user_id = $this->session->userdata('user_id');
//load pheeds
$dt = $this->pheed_model->get_latest_pheeds($limit,$offset);
$data = $dt['pheeds']; //data
$total = $dt['total']; //Total no of rows of data
$return['pheeds'] = $data;
echo json_encode($return); //encode in json
} else {
$this->output->set_status_header('401',"Attempting Unauthorized Access");
}
}
How do I break this data into pages, so I can simply pass the page no as argument to method via the ajax call to implement the load more with jQuery?
Calculate $offset by multiplying (page number - 1) with $limit:
$offset = ($page - 1) * $limit;
So if $page is 1, then it will be (1 - 1) * 20 = 0 * 20 = 0,
if $page is 2, then it will be (2 - 1) * 20 = 1 * 20 = 20
Also rename function parameter $offset to $page
[EDIT]
Also what i would do is to query one row more, than needed, so i can detect if there is next page, eg:
$dt = $this->pheed_model->get_latest_pheeds($limit + 1,$offset);
$next_page = false;
if (count($dt) > $limit) {
$next_page = true;
$dt = array_pop($dt); // Excluding the last row so it is same size as $limit
}
// More code....
$return['next_page_exists'] = $next_page;

PHP and Timer events

I would like to use a Timer in php, sending messages after a certain period of time (no player activity)? This is for a multi-player game through sockets.
I have googled and stackoverflew and found the following
could use a cron (will need to
synronize my php classes (socket
based) with the cron... ), No I
guess.
could use sleep ... if it could wait
for less than one second, I will have
given a try, No again, I guess
could use register_tick_function ...
not applicable I think
Any ideas?
Thanks!
This is what I wrote to deal with my timing needs. It doesn't magically interrupt your code, but it provides a very flexible way to schedule timers. All you have to do, is make sure you run $events->CheckTimers() every now and then.
The libevent module does a lot more, but that's a bit more effort.
$events = new Events();
function callback($text) {
printf("I'm a timer callback %s\n", $text);
}
$events->AddTimer("5s", "callback", "every 5 seconds", EVENTS::EVENT_REPEAT);
$events->AddTimer("2s..15s", "callback", "random time 2 to 15 seconds", EVENTS::EVENT_REPEAT);
$events->AddTimer("1m", create_function('', "echo 'Im a LAMBDA function that runs every minute\n';"), false, EVENTS::EVENT_REPEAT);
$events->AddTimer("1h..2h", "callback", "I will run once, in between 1 and 2 hours");
# This is just an example, in reality, you would make sure to call CheckTimer() regulary (ideally not more than once a second)
while (true) {
$events->CheckTimers();
printf("Next timer in %s seconds...\n", $ne = $events->GetNextTimer(), gettype($ne));
sleep(1);
}
class Events {
const EVENT_REPEAT = 0x0001;
const EVENT_SEQUENCE = 0x0002;
var $events;
var $timers;
function __construct() {
$this->events = array();
$this->timers = array();
}
function AddTimer($when, $action, $args = false, $flags = 0) {
if (preg_match('#([0-9a-zA-Z]+)..([0-9a-zA-Z]+)#', $when, $a)) {
$time = time(NULL) + rand($this->time2seconds($a[1]), $this->time2seconds($a[2]));
} else {
$time = time(NULL) + $this->time2seconds($when);
}
if ($flags & self::EVENT_SEQUENCE) {
while ($this->IsArrayCount($this->timers[$time])) {
$time ++;
}
}
$this->timers[$time][] = array("when" => $when, "action" => $action, "args" => $args, "flags" => $flags);
ksort($this->timers);
}
function GetNextTimer() {
if (!$this->IsArrayCount($this->timers)) {
return false;
}
reset($this->timers);
$firstevent = each($this->timers);
if ($firstevent === false) {
return false;
}
$time = $firstevent["key"];
$nextEvent = $time - time(NULL);
if ($nextEvent < 1) {
return 1;
}
return $nextEvent;
}
function CheckTimers() {
$rv = false;
$now = time(NULL);
foreach ($this->timers as $time => $events) {
if ($time > $now) {
break;
}
foreach ($events as $key => $event) {
# debug("Event::CheckTimer: {$event["action"]}");
# ircPubMsg("Event::CheckTimer: {$event["action"]}", "#bots");
if (!$event["args"]) {
call_user_func($event["action"]);
} else {
$rv = call_user_func_array($event["action"], is_array($event["args"]) ? $event["args"] : array($event["args"]));
}
unset($this->timers[$time][$key]);
if ($event["flags"] & self::EVENT_REPEAT) {
$this->AddTimer($event["when"], $event["action"], $event["args"], $event["flags"]);
}
if ($rv) {
# break;
}
}
if (!$this->IsArrayCount($this->timers[$time])) {
unset($this->timers[$time]);
}
if (0 && $rv) {
break;
}
}
if ($rv) {
return $rv;
}
}
function time2seconds($timeString) {
$end = substr($timeString, strlen($timeString) - 1);
$seconds = intval($timeString); // = preg_replace("#[^0-9]#", "", $a);
if (is_numeric($end)) {
return $seconds;
}
$unim = array("s","m","h","d", "w", "m", "y");
$divs = array(1, 60, 60, 24, 7, 28, 12, false);
$found = false;
while (!$found) {
$u = array_shift($unim);
$d = array_shift($divs);
$seconds *= $d;
if ($end === $u) {
return $seconds;
}
}
return intval($timeString);
}
function IsArrayCount($possibleArray) {
return (isset($possibleArray) && is_array($possibleArray)) ? count($possibleArray) : false;
}
}
Does PHP's time_nanosleep() work for you? Or usleep()?
Maybe a daemon?
http://kevin.vanzonneveld.net/techblog/article/create_daemons_in_php/
here are a few concepts how to do it :
1. common concept is to create script for sending messages, then add it to server Cron application and execute the script with specified time.
2. write python script that will control your php application file or section, in pythonic terms you can fork process on server start that will do your tasks every amount of time (with infinity loop I guess ... while 1: ..)
3. write shell .sh file that will invoke php or python script and add controls of this script it to /etc/init.d to be more controllable.

Categories