Evaluating php code stored in database - php

I have several strings stored in a database (yes, I know it's not the best practice, but I'm working with a system someone else designed and I cannot change it.)
For example, in my table called specialDates, I have a computedDate column that contains this:
date('d', strtotime("thursday, november ".date("Y")." + 3 weeks"))
This is pulled into my code and stored in a variable called $request['order_date'].
This, when used in standard PHP code, returns the date that Thanksgiving falls on in the current year. I need to pass the evaluated value of this (for this year - 2013 - the value is 28) to another query. But I can't seem to get the value to evaluate.
$query = 'SELECT count(orderID) as numberOfOrders FROM customer_orders WHERE customerID = ? AND orderDate = ?';
$param = array($request['customer_id'], eval($request['order_date']));
doesn't work. And when I just try to echo out the value to the screen, doing this:
echo eval($request['order_date']);
or this:
echo eval(" return \$request['order_date']; ");
just prints out the literal value of the string (i.e. date('d' etc.) rather than the expected evaluated value.
What am I doing wrong?
UPDATED
I tried AScherer's answer below, and although it does work when I just echo the value to the screen:
echo eval(" return {$request['order_date']}; ");
it does not work when I try to use the eval inside my array:
$param = array($request['customer_id'], eval("return {$request['order_date']}"));
How can I get this working so that the value I'm passing in the array is the actual value of 28, rather than the string pre-eval?

You were escaping the $request in your return part, which you dont want to do. This method should work, but id suggest adding return the the row in the database so u dont have to modify the eval
$sql = "SELECT customer_id, CONCAT( 'return ', order_date, ';' ) as function from customer_orders WHERE customerID = ? AND orderDate = ?";
$param = array( $request[ 'customer_id' ], eval( $request[ 'function '] ) );
---
OR
---
$evalData = eval(" return {$request['order_date']}; ");
$param = array($request['customer_id'], $evalData );

Yes, you can change it. If not to a sensible result, then to a useful result nontheless.
Your input data is a string:
date('d', strtotime("thursday, november ".date("Y")." + 3 weeks"))
This is an information to "calculate Thanksgiving of this year". You can set up a lookup table that detects this string and the needed function to execute:
$dateCalculations = array(
'date(\'d\', strtotime("thursday, november ".date("Y")." + 3 weeks"))' => function()
{
return date('d', strtotime("thursday, november ".date("Y")." + 3 weeks"));
}
'date(\'...whatever else is in the system...' => function(){}
// alias names also work
'thanksgiving' => function()
{
return date('d', strtotime("thursday, november ".date("Y")." + 3 weeks"));
}
);
You can then try to find the string from the database in the array and instantly have the function you need to call:
$thanksgiving = $dateCalculations[$dbvalue]();
From here you can go anywhere. Note that this will also work with the alias name "thanksgiving", so you might be able to replace it in the database if you know where else this braindead approach is also used... If not, at least you tried your best.

Related

Warning: Trying to access array offset on value of type int in

This code is giving error. I have gone through previous questions. I have used gettype() and it shows that my data is integer. I have tried to convert it to string by using strval() but it didnt work.
I saw this but in dont know how this can be implemented with my code.
sugested similar questions talk about undefined variables.
My problem not undefine but that its value type. variables are defined. It is stored in db as string but when i check its variable type using gettype(), it is an integer. and it seems foreach() doesnt work with integer.
If anyone can help please. i am still in the learning stage.
foreach($schedule_data as $schedule_row)
{
$end_time = strtotime($schedule_row["agent_schedule_end_time"] . ':00');
$start_time = strtotime($schedule_row["agent_schedule_start_time"] . ':00');
$total_agent_available_minute = ($end_time - $start_time) / 60;
$average_inspection_time = $schedule_data["average_inspection_time"];
}
i wrote query
SELECT * FROM agent_schedule_table
WHERE agent_schedule_id = '$agent_schedule_id'
data stored in $schedule_data var_dump ()
array(8) {
["agent_schedule_id"]=> int(18)
["agent_id"]=> string(7) "S1O0NWE"
["agent_schedule_date"]=> string(10) "2022-08-18"
["agent_schedule_day"]=> string(8) "Thursday"
["agent_schedule_start_time"]=> string(5) "08:35"
["agent_schedule_end_time"]=> string(5) "22:35"
["average_inspection_time"]=> int(60)
["agent_schedule_status"]=> string(6) "Active"
}
foreach()
var_dump($end_time); = int(1660595700)
//Agent create appointment for himself
Agent add through a form that has Date: ..., starttime: ...., averagetime: ...., endtime:.....
i wrote query to select from appointemnt the agent appointment time.
i used while() for the stmt-> excute
Problem 1: while loop make it repeat same date and time so many times.
I tried using foreach() or for(), it is not working. I dont know if am using it wrongly or just that it wont work.
Problem 2: what i want to achieve is that the table should;
for every date, role1 start time, role2 start time + average time, role 3 role2time + average time. so the output will be like
peter 22/08 4:00
peter 22/08 4:30,
peter 22/08 5:00 etc
$sql = "SELECT * FROM agent_schedule_table
INNER JOIN agent
ON agent.agent_id = agent_schedule_table.agent_id
INNER JOIN property
ON property.agent_id = agent.agent_id
INNER JOIN rent_interest
ON rent_interest.Property_number = property.Property_number
WHERE (agent_schedule_table.agent_schedule_date >= '$todaysdate' AND property.Property_number = '".$_SESSION["apartment_number"]."')
ORDER BY agent_schedule_table.agent_schedule_date ASC";
$stmt = $pdo->prepare($sql);
$stmt ->execute(array());
$rows = array();
while ($row = $stmt->fetch(PDO::FETCH_ASSOC) ) {
$result = $row;
}
I don't think you need a loop. $schedule_data is an associative array, just access the element from there, not from a nested element.
$end_time = strtotime($schedule_data["agent_schedule_end_time"] . ':00');
$start_time = strtotime($schedule_data["agent_schedule_start_time"] . ':00');
$total_agent_available_minute = ($end_time - $start_time) / 60;
$average_inspection_time = $schedule_data["average_inspection_time"];

PHP - Select data from where timestamp is

I have a piece of code which will select x number of days into the future and print it out.
I'm then trying to select data from those timestamps, and print out accordingly:
Below I am selecting the number of days in the future it should loop ($max) and how many rows/data there is ($data["cnt"])
$stmt=$dbh->prepare("select round((expire - unix_timestamp()) / 86400) as days, count(*) as cnt from xeon_users_rented WHERE user_by=:username group by days;");
$stmt->bindParam(":username",$userdata['username']);
$stmt->execute();
$data=$stmt->fetchAll();
$max = max(array_map(function($d){
return $d['days'];
}, $data));
$expireData = array();
I then loop through x number of days in the future and print it out: (Let's say that $x is = 10)
for($x = 0; $x <= $max; $x++){
if ($data[$x]["cnt"] > 0){
$expireData[] = $data[$x]["cnt"];
}else{
$expireData[] = 0;
}
$stamp = strtotime('+'.$x.' day', time());
$expireDays[] = date("Y/m/d", $stamp);
}
I then print out the days data and the data:
<?php echo implode("', '", $expireDays); ?>
<?php echo implode("', '", $expireData); ?>
Which gives me:
'2014/11/05', '2014/11/06', '2014/11/07', '2014/11/08', '2014/11/09', '2014/11/10', '2014/11/11', '2014/11/12', '2014/11/13', '2014/11/14', '2014/11/15'
and (where each digit represent a value for that specific date)
2,8,0,0,0,0,0,0,0,0
So far so good. The only problem here is, that the data (2,8,0,0etc.) is not correct. It should for example be:
0,0,2,0,0,0,8,0,0,0
My question is: How can I print out the data, where it matches the timestamp (xeon_users_rented.expire)?
To simplify my answer from before and to answer your question directly "How can I print out the data, where it matches the timestamp"?
You need to first put the unix timestamp of "strtotime('+'.$x.' day', time());" into an array from your original loop. Remove the expiredays[] stuff from that loop.
Then loop through that array and then use array_search for finding any matching indexes in the $data array.
if (found in $data array)
$expireDays[] = $data[array_search position]['cnt'];
else
$expireDays[] = 0;
From what I have gathered in what you are trying to establish, the sql query (for example) returns an array such as:
$data = array(
array("days"=>232975857, "cnt"=> 4),
array("days"=>232975867, "cnt"=> 10),
array("days"=>232976689, "cnt"=> 0),
array("days"=>232976688, "cnt"=> 2)
);
The max in your case is 10. However, please note that your code (below):
$max = max(array_map(function($d){
return $d['days'];
}, $data));
could return a lot of PHP E_NOTICE errors and be slow because you are working out a maximum from the unix_timestamp at that stage which is for example 232975867 (far too many loops I suspect that you need). The max should be worked out in the following way I suspect:
$max = count($data);
In my case (from my data example example) this will return something like 4 for which your for loop code will need to reference "<" not "<=". To optimise this I would actually put straight into the for loop "...; $x < count($data); ...;" unless of course you need the $max later.
Here is a big issue for me. I don't see where currently you have any correlation between the $stamp variable and the "days" column from your sql statement. Perhaps I have not seen enough information from you to fully understand or I am interpreting your question incorrectly but your sql for one will not necessarily return the same dates as the stamp variable will calculate and will not certainly return a cnt of 0 for any dates that do not exist in that table. This is why:
if ($data[$x]["cnt"] > 0){
part of the section is unnecessary and possibly incorrect.
To answer your question why do you get "2,8,0,0,0,0...." instead of the order you expected is because the sql does not return 0 cnt values as quite simply the date does not exist in it's table and your implode still returns '0's appended as you forcibly added the 0's afterwords with the line:
$expireData[] = 0;
First of all, you need to fill your data (or re-write your data to contain cnt of '0's in the correct array places). You can achieve this from the sql level with a subquery that ensures missing dates are contained and then a cnt value of 0 is enforced. I'll leave this to you to work out however another way (via PHP) is to do the following (pseudo code):
place each 'stamps' (in unix format) in array from previous loop
forloop $i through $stamps
array_search $stamps against $data['days']
if (found)
$expireDays[] = $data[array_search position]['cnt'];
else
$expireDays[] = 0;
This means that you remove the $expireDays from your first loop.
Finally, perhaps I have misunderstood and that your 'days' column shouldn't match your $stamp dates as those dates are in the future and your 'days' columns are in the past. In this case, your only option is to adjust your sql statement to forcibly include dates that are missing (between a certain date range)
Good luck.

MySQL/PHP - Filter on numeric values on fields that are not numeric

Basically, the idea is that people filter search results on the length. However, length is stored in a text field, as this can be different from item to item. An item could be 16,20 metres, and another could be 8.1m.
How would one even start? Get all the possible values from the database, change them to the format that is filtered on (parse everything to numeric only, comma separated?), get the associated ID, and then only show all the info related to those IDs, or is there a way I haven't found yet?
Kind regards.
edit: Standardizing format is a solution, but not one I can apply in this situation. I am not allowed to do this. It gets worse - the filtering can have both a minimum and a maximum value. Minimum: 4 and maximum: 8 should show everything between those lengths. 6.1m, 7,82 metres, 5.
Because I couldn't change the way the database was set up (standardize is, keep separate fields for the length itself, a float/double, and a field for the appendix), I've decided to go with this approach.
First get all the possible lengths, then:
foreach($lengths as $length) {
$cLengths[$length['item_id']] = preg_replace("/[^0-9,.]/", "", str_replace(',', '.', $length['field_value']));
}
Assuming the page would then be called with &minLength=2&maxLength=10 in the URL:
$minLength = $_GET['minLength'];
$maxLength = $_GET['maxLength'];
if(!is_null($minLength) && !is_null($maxLength)) {
$filteredItems = '';
foreach($cLengths as $itemId => $cL) {
if($cL >= $minLength && $cL <= $maxLength) {
$filteredItems .= $itemId . ',';
}
}
$filteredItems = substr($filteredItems, 0, -1);
$where .= 'item_id IN(' . $filteredItems . ') AND ';
}
I would recommend to standardize a format for length. It is hard to filter numeric values stored in different formats.
You can use the LIKE operator to search for any pattern in a string:
SELECT * FROM table WHERE length LIKE '%filtervalue%'
I would simply enforce standard during your query. Assuming your length column is named "length" and you query table is "table":
SELECT something, replace(length,',','.') + 0 as mylen FROM `table` HAVING mylen BETWEEN 16.2 AND 18
It would not be very fast, you can also use replace + 0 directly in where, it would remove the need for HAVING that is:
SELECT something FROM `table` replace(length,',','.') + 0 BETWEEN 16.2 AND 18
Good Luck!

preg_match for mysql date format

im trying to validate a date to see if it matchs the mysql format
this is the code
$match = "/^\d{4}-\d{2}-\d{2} [0-2][0-3]:[0-5][0-9]:[0-5][0-9]$/";
$s = $this->input->post("report_start"). " " . $this->input->post("report_start_time").":00";
$e = $this->input->post("report_end"). " " . $this->input->post("report_end_time").":59";
if($this->input->post("action") != "")
{
echo trim($s). " => " . preg_match($match, trim($s));
echo "<br>";
echo trim($e). " => " . preg_match($match, trim($e));
}
the date format goes into $s and $e are
$s = 2011-03-01 00:00:00
$e = 2011-03-01 23:59:59
and they both return false (0).
i tested the pattern on http://www.spaweditor.com/scripts/regex/index.php and it returns true (1)
http://pastebin.com/pFZSKYpj
however if i manual inter the date strings into preg_match like
preg_match($match, "2011-03-01 00:00:00")
it works.
i have no idea what im doing wrong
======================
now that i think about it, i only need to validate the houre:min part of the datetime string.
im manually adding the seconds and the date is forced by a datepicker and users cant edit it
You're making your work harder that it needs to be. In php there are many date handling functions that mean you don't have to treat dates like strings. So, rather than test that your input dates are in the correct format, just insist on the correct format:
$adate= date_create('January 6, 1983 1:30pm'); //date format that you don't want
$mysqldate= $adate->format("Y-m-d h:i:s");//date format that you do want
There are also functions to check that a date is a real date, like checkdate.
ok heres wat i did.
since im forcing the date format and the ending seconds of the time part
i just validated the hour:mini part using "/^2[0-3]|[01][0-9]:[0-5][0-9]$";
and if that returns true i put everything together end reconstructed the final datetime string
$match = "/^2[0-3]|[01][0-9]:[0-5][0-9]$/";
$s_d = $this->input->post("report_start");
$s_t = $this->input->post("report_start_time");
$e_d = $this->input->post("report_end");
$e_t = $this->input->post("report_end_time");
if($this->input->post("action") != "")
{
if(
( preg_match($match , trim($s_d." ".$s_t.":00")) )
&& ( preg_match($match , trim($e_d." ".$e_t.":59")) )
)
{
$r = $this->model_report->client_hours_logged(array($s,$e));
$data['report'] = $r;
var_dump($r);
//$this->load->view("report/client_hours_per_client",$data);
}
}
Watch out:
[0-2][0-3] is not a good regex for hour values - it will match 01, 12, 23 and others, but it will fail 04 through 09 and 14 through 19.
Better use (2[0-3]|[01][0-9]) instead.
I use this to validate a 'Y-m-d H:i:s' format date string:
match = '/^[12][0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[01]) ([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]$/';
You could use strtotime and date to parse and format the date properly.
Why not just simply force the date into the format you want:
$e = '2011-03-01 00:00:00';
$mysqlFormat = date('Y-m-d H:i:s', strtotime($e));
Also, there is a bit of an error in your regex [0-2][0-3]:[0-5][0-9]:[0-5][0-9] will only match the hours of 00,01,02,03,10,11,12,13,20,21,22,23 so it will never match 4am, or 3pm among others. That aside I looked over your RegEx and I don't see any problems with it matching the test cases you've offered. I would check to make sure there is not extra whitespace on either side of date string with trim().
I concur with Tim : MySQL behaves in quirks mode and always tries to go easy on DATE and DATE_TIME column types. You can omit certain parts of your input and it still will try to compensate and achieve that goal successfully to some degree... That's why, most numbers your Reg-ex considers as invalid, MySQL will accept as valid.

Outputting the name of the month instead of the number

I have a query which returns 3 fields, one of which is the month as a two digit number.
I want to basically have it so if month == 1 output january, if month == 02 output febuary etc
This is what I am trying, but this does not work at all, and prevent the entire column from being displayed in PHP.
while ($row = mysql_fetch_array($sqlstr)) {
if ($row['theMonth']=="6") {
echo "<td>{June}</td>";}
echo "<td>{$row['sumSales']}</td>";
echo "<td>{$row['sumPurchases']}</td>";
echo "</tr>";
}
}
What is the correct way to do what I want, and why is what I am doing wrong?
The SQL query I am using is:
SELECT theMonth, sum(Sales) as sumSales, sum(Purchases) as sumPurchases
FROM
( SELECT date_format(saledate, '%Y-%m') AS theMonth, sales.cost as Sales, 0 AS Purchases
FROM sales, products
WHERE sales.product=products.name AND category='Food' OR category='Bocas'
OR category='Bebidas' OR category='Flor de cana por botellas'
OR category='Vino por botella' OR category='hora feliz'
UNION ALL
SELECT date_format(purchasedate, '%Y-%m') AS theMonth, 0 as Sales, purchases.cost as Purchases
FROM purchases
) AS all_costs
group by theMonth
I donĀ“t think I could just replace
SELECT date_format(purchasedate, '%Y-%m') AS theMonth
with
SELECT MONTHNAME(purchasedate) AS theMonth
So what would be the best way to return the month name as text in SQL?
In your SQL you can use DATE_FORMAT to convert a date to a month name:
SELECT DATE_FORMAT(NOW(), '%M')
July
The list of allowable specifiers can be found in the MySQL documentation.
(MONTHNAME should also work too.)
The reason why your current method doesn't work is because you are currently outputting both the year and the month (e.g. "2010-06") and this string doesn't compare equal to the string "6".
.
function month_name($int) {
return date( 'F' , mktime(1, 1, 1, (int)$int, 1) );
}
echo month_name(2); // February
First option would be to modify your SQL query to return the month as a name rather than (or as well as) a numeric. See MONTHNAME
Second option would be to use PHP's date functions to generate the name for you
$monthName = date('F',mktime(1,1,1,$row['theMonth'],1,2010));
Third would be to use a monthnames array, similar to zebediah's suggestion
There is probably a php builtin for that, but not using anything like that
$monthNames = array(1 => "January", 2 => "Febuary", 3 => "March", .... 12 => "December");
while ($row = mysql_fetch_array($sqlstr)) {
echo "<td>{$monthNames[$row['theMonth']]}</td>";
echo "<td>{$row['sumSales']}</td>";
echo "<td>{$row['sumPurchases']}</td>";
echo "</tr>";
}
You've got a closing curly brace at the end of the line on your first echo statement. That's causing PHP to prematurely terminate the conditional block, then it has a parse error when it stumbles across your last closing curly brace since it doesn't have an opening match.
You can get the name of the month from a timestamp (if you have one) with the date function. date('F', $timestamp); see the php date function reference
Doing it in the SQL statement is probably your easiest and most performance-friendly way of handling this particular situation.

Categories