Converting .Net API to PHP - php

I have this .Net REST API function modified from the demo for a grid control here: http://gijgo.com/grid/demos/ajax-sourced-data.
However, I am using PHP on the backend.
public JsonResult Get(int? page, int? limit)
{
List<Models.inventory> records;
int total;
using (ApplicationDbContext context = new ApplicationDbContext())
{
var query = context.inventory.Select(p => new Models.inventory
{
id = p.id,
company = p.company,
part = p.part,
year = p.year,
model = p.model,
stock = p.stock,
ic = p.ic,
vin = p.vin,
status = p.status,
bodycolor = p.bodycolor,
condition = p.condition,
comments = p.comments,
miles = p.miles,
price = p.price,
qty = p.qty
});
query = query.OrderBy(q => q.id);
total = query.Count();
if (page.HasValue && limit.HasValue)
{
int start = (page.Value - 1) * limit.Value;
records = query.Skip(start).Take(limit.Value).ToList();
}
else
{
records = query.ToList();
}
}
return this.Json(new { records, total }, JsonRequestBehavior.AllowGet);
}
I have converted the function to PHP but am having difficulty with the pagination because the total records isn't really being sent.
The C# code, filters the data after the query and i'm not sure how to do that with PHP and PostgreSQL.
I also want to return the total number of rows without the limit and offset in the result I suppose I'm going to have to run a 2nd query to return that data,
is that correct or can I do it in another way?
private function GetInventory()
{
$ic=$_request['ic'];
$limit=$_request['limit'];
$offset=$_request['page']-1;
$sql = "SELECT u.id, "
. " (SELECT company FROM urgss.users WHERE id = u.id) AS company, "
. " u.itemname || ' (' || u.part || ')' as part, "
. " u.year, "
. " u.model, "
. " u.stockno AS stock, "
. " u.ic AS ic, "
. " u.vin, "
. " u.status || ' / ' || u.currentstatus AS status, "
. " REGEXP_REPLACE(u.bod_col, '[\[\]]', '', 'g') AS bodycolor, "
. " u.condition, "
. " u.comments, "
. " CASE "
. " WHEN u.miles::integer < 1000 THEN "
. " u.miles::INTEGER * 1000 "
. " ELSE "
. " u.miles::INTEGER "
. " END AS miles, "
. " CASE "
. " WHEN u.rprice > 0 THEN "
. " u.rprice "
. " ELSE "
. " NULL "
. " END AS price, "
. " u.qty "
. "FROM unet u "
. "WHERE ic = '" . $ic. "' "
. "AND year::integer > 0"
. " LIMIT " . $limit . " OFFSET ". ($offset * $limit);
$result = pg_exec($db, $sql);
$rows = pg_fetch_all($result);
echo json_encode($rows);
}

If you remove LIMIT from the query (REMOVE THIS . " LIMIT " . $limit . " OFFSET ". ($offset * $limit);), then there are two options:
Instead of pg_fetch_all you could fetch in a loop and specify the $row_num based on offset and limit:
//get total number of rows
$total = pg_num_rows($result);
//get rows from offset up to limit
$row_num = $offset;
while($row_num < ($offset + $limit) && $rows[] = pg_fetch_assoc($result, $row_num)) {
$row_num++;
}
echo json_encode($rows);
Or pg_fetch_all and slice what you want:
//get total number of rows
$total = pg_num_rows($result);
//get ALL rows
$rows = pg_fetch_all($result);
//get rows from offset up to limit
$rows = array_slice($rows, $offset, $limit);
echo json_encode($rows);
Not sure what new { records, total } does in .NET, but you could return one of these:
return json_encode([$rows, $total]);
//or
return json_encode(['rows' => $rows, 'total' => $total]);

Related

Pass optional SQL to prepared statement

I try to inject some optional SQL to prepared statement with the parameter $and:
public function loadInfoAndStatus($property_id, $property_item_type_id, $and, $returnArray = false)
{
if (!isset($property_id) || empty($property_id)
|| !isset($property_item_type_id) || empty($property_item_type_id)
|| !isset($and) || empty($and)) {
error_log(get_class() . " - " . __FUNCTION__ ." : required params not set or empty");
return false;
}
$sql = " SELECT pi.status, pi.info, pi.property_item_id "
. " FROM ". self::TABLE ." pi "
. " JOIN countries c ON c.country_id = pi.country_id "
. " WHERE pi.property_id = ? "
. " AND property_item_type_id = ? "
. $this->con->real_escape_string($and) // <--- here
. " ORDER BY pi.status "
. " DESC LIMIT 0,1";
$err = "";
if (!$stmt = $this->con->prepare($sql)) {
$err .= "Prepare failed: (" . $this->con->errno . ") " . $this->con->error;
}
...
But if I call the function e.g.
$row2 = Main::getModel("Property/Item")->loadInfoAndStatus(
$id
, $property_item_type_id
, " AND c.iso = 'DE' "
, true
);
Hint: $and can be one of:
" AND c.iso <> 'DE' AND c.european <> 1 "
" AND c.iso <> 'DE' AND c.european = 1 "
" AND c.iso = 'DE' "
Then I get "Prepare failed" but there is no error message.
Resulting SQL:
SELECT pi.status, pi.info, pi.property_item_id FROM property_item pi JOIN countries c ON c.country_id = pi.country_id WHERE pi.property_id = ? AND property_item_type_id = ? AND c.iso = \'DE\' ORDER BY pi.status DESC LIMIT 0,1
It works if I don't use real_escape_string
Do I have to create new functions for each new sql, or is there another way?
You have to list all possible variants in your function.
This is a toilsome task but you have to realize that's the only way.
public function loadInfoAndStatus($property_id, $property_item_type_id, $iso = null, $european = null, $returnArray = false)
{
if (empty($property_id) || empty($property_item_type_id)) {
error_log(get_class() . " - " . __FUNCTION__ ." : required params not set or empty");
return false;
}
$parameters = [$property_id, $property_item_type_id];
$sql = " SELECT pi.status, pi.info, pi.property_item_id "
. " FROM ". self::TABLE ." pi "
. " JOIN countries c ON c.country_id = pi.country_id "
. " WHERE pi.property_id = ? "
. " AND property_item_type_id = ? ";
if ($iso) {
$sql .= " AND c.iso <> ? ";
$parameters[] = $iso;
}
if ($european === true) {
$sql .= " AND c.european == 1 ";
} elseif ($european === false) {
$sql .= " AND c.european <> 1 ";
}
$sql .= " ORDER BY pi.status ";
$sql .= " DESC LIMIT 0,1";
$stmt = $this->con->prepare($sql);
$stmt->bind_param(str_repeat("s", count($parameters)), ...$parameters);
$stmt->execute();
I also removed some cargo cult code from your method, in case you are interested why
Do you really need to check for both isset() and empty() at the same time?
PHP error reporting
I solved the problem by using a whitelist method:
public function loadInfoAndStatus($property_id, $property_item_type_id, $and = "", $returnArray = false)
{
if (empty($property_id) || empty($property_item_type_id) || empty($and)) {
error_log(get_class() . " - " . __FUNCTION__ ." : required params not set or empty");
return false;
}
if (!$this->isSqlInWhitelist($and, array(
"AND c.iso = 'DE'"
,"AND c.iso <> 'DE' AND c.european = 1"
,"AND c.iso <> 'DE' AND c.european <> 1"
))) {
error_log(get_class() . " - " . __FUNCTION__ ." : sql is not in whitelist.");
return false;
}
$sql = " SELECT pi.status, pi.info, pi.property_item_id "
. " FROM ". self::TABLE ." pi "
. " JOIN countries c ON c.country_id = pi.country_id "
. " WHERE pi.property_id = ? "
. " AND property_item_type_id = ? "
. $and
. " ORDER BY pi.status "
. " DESC LIMIT 0,1";
$stmt = $this->con->prepare($sql);
...
...
protected function isSqlInWhitelist($sql, $whitelist)
{
if (!empty($sql)) {
if (!in_array(trim($sql), $whitelist)) { return false; }
}
return true;
}

Check if two ranges intersect in a database with php

I have a database that has 2 columns Left_From and Left_To I need to basically check both columns with each row in the database to see if there is any overlapping ranges. So lets say there are 37 rows returned I need to check each row 37 times. I have tried array_intersect() with ranges and multiple loops. I have also tried BETWEEN in mysql but that does do what I need it to either. When I tried the between method I have two loops that I thought would take these two
$newstart[$crow] = $row['LEFT_FROM'];
$newend[$crow] = $row['LEFT_TO'];
and compare them to the new data that would be looped through 37 times because of $row2.
//attempt at BETWEEN
$newstart = array();
$newend = array();
$crow = 0;
while ($row = mysqli_fetch_array($get)) {
$newstart[$crow] = $row['LEFT_FROM'];
$newend[$crow] = $row['LEFT_TO'];
while ($row2 = mysqli_fetch_array($get)) {
$newsql = "SELECT * FROM database+table WHERE tablename = 'something' AND
LEFT_FROM BETWEEN " . $newstart[$crow] . " AND " . $newend[$crow] . " OR
LEFT_TO BETWEEN " . $newstart[$crow] . " AND " . $newend[$crow] . " OR ".
$newstart[$crow] . " BETWEEN " . "LEFT_FROM" . " AND ". " LEFT_TO";
$result = mysqli_query($GLOBALS['Con'], $newsql);
if (!$result) {
echo "Error: " . mysqli_error($GLOBALS['Con']) . "<br>";
}
if (!empty($result)) {
echo "Overlap: ". "Row2 LEFT_FROM: " . $row2['LEFT_FROM'] . " NewStart: " . $newstart[$crow] . " Row2 LEFT_TO: " . $row2['LEFT_TO'] . " Newend: " . $newend[$crow] . "<br>" . "Crow: " . $crow . "<br>" ;
}
}
echo "Crow: " . $crow . "<br>";
$crow++;
}
atempt at array_intersect all variables in arrays are set to 0
$result = mysqli_query($GLOBALS['con'], $select);
$Rows = $result->num_rows;
$Rows2 = $Rows;
$Rows3 = $Rows;
$Rows4 = $Rows;
$Rows5 = $Rows;
$range1 = array();
$range2 = array();
$range3 = array();
$range4 = array();
while ($counter <= $Rows) {
$range1[$crow] = $leftfrom[$add];
$range2[$crow] = $leftto[$add];
$counter++;
$road++;
$crow++;
}
while ($counter2 <= $Rows2) {
$range3[$crow2] = $leftfrom[$add2];
$range4[$crow2] = $leftto[$add2];
$counter2++;
$road3++;
$crow2++;
}
$Combined1 = array();
$Combined1 = array();
while ($counter3 <= $Rows3) {
$Combined1[$crow5] = range($range1[$crow3], $range2[$crow3]);
$Combined2[$crow6] = range($range3[$crow3], $range4[$crow3]);
$crow5++;
$crow6++;
$crow3++;
$counter3++;
}
$check1 = 0;
while ($check1 <= $Rows4) {
$GLOBALS['check2'] = 0;
$Rows6 = $GLOBALS['check2'] + 1;
while ($GLOBALS['check2'] <= $Rows5) {
$results = array_intersect($Combined1[$check1],$Combined2[$Rows6]);
if ($results) {
$start = reset($results);
$end = end($results);
echo "These are overlapping" . "<br>";
echo "Start of overlap: " . $start . " Rows#: " . $check1 . " Bad Row: " . $GLOBALS['check2'];
echo "<br>";
echo "end of overlap: " . $end;
echo "<br>" . $GLOBALS['check2'] ;
$GLOBALS['check2']++;
}else{
echo "<br>" . $check1 . " No duplicates" . "<br>";
$GLOBALS['check2']++;
}
}
$check1++;
}
You don't need a loop in PHP, you can do it entirely by joining the table with itself.
SELECT *
FROM yourTable AS t1
JOIN yourTable AS t2
ON t1.id < t2.id
AND (t1.left_from <= t2.left_to AND t2.left_from <= t1.left_to)
t1.id < t2.id keeps it from treating a row as overlapping with itself (and using < rather than != keeps it from showing the same pair of rows twice). Replace id with the primary key of your table.
To check, if two number ranges overlap, you could use the simple test x1 < y2 AND y1 < x2. This could be combined in a single sql statement.
SELECT
t1.LEFT_FROM as LEFT_FROM_1,
t1.LEFT_TO as LEFT_TO_1,
t2.LEFT_FROM as LEFT_FROM_2,
t2.LEFT_TO as LEFT_TO_2
FROM
t t1, t t2
WHERE
t1.LEFT_FROM < t2.LEFT_TO AND t2.LEFT_FROM < t1.LEFT_TO
This query would return all overlapping ranges.

Passing ID value from one table to another from drop down selection

What am I missing?
I have a drop down with values. I think everything is working fine, except when I post the results to another table I can't seem to get the gameID from the first table to post, it just goes through as blank. Am I missing an association with the team and the gameID?
Query to get data for drop down:
$sql = "select s.*, (DATE_ADD(NOW(), INTERVAL " . SERVER_TIMEZONE_OFFSET . " HOUR) > gameTimeEastern or DATE_ADD(NOW(), INTERVAL " . SERVER_TIMEZONE_OFFSET . " HOUR) > '" . $cutoffDateTime . "') as expired ";
$sql .= "from " . DB_PREFIX . "schedule s ";
$sql .= "inner join " . DB_PREFIX . "teams ht on s.homeID = ht.teamID ";
$sql .= "inner join " . DB_PREFIX . "teams vt on s.visitorID = vt.teamID ";
$sql .= "where s.weekNum = " . $week . " ";
$sql .= "order by s.gameTimeEastern, s.gameID";
//echo $sql;
$query = $mysqli->query($sql) or die($mysqli->error);
if ($query->num_rows > 0) {
$i = 0;
while ($row = $query->fetch_assoc()) {
$sGameID = (int)$row['gameID'];
$homeTeam = new team($row['homeID']);
$visitorTeam = new team($row['visitorID']);
$surv_pick_options_h[$i]=$row['homeID'];
$surv_pick_options_v[$i]=$row['visitorID'];
if ($row['expired']){
$surv_pick_expired_h[$i]=$row['homeID'];
$surv_pick_expired_v[$i]=$row['visitorID'];
}
$surv_gameID[$i] = (int)$row['gameID'];
$i++;
$rowclass = (($i % 2 == 0) ? ' class="altrow"' : '');
}
};
Drop down select option:
$sWeek = (int)getCurrentWeek()+1;
if ($week < $sWeek){
$survpicks_to_disable = array_slice($survpicks,0,$week-1);
$disabled = array_merge($survpicks_to_disable,$surv_pick_expired_h,$surv_pick_expired_v);
echo '<select name="survpick" id="survpick">
<option default>Select</option>';
foreach($surv_pick_options_h as $home){
echo '<option value="'.$home.'"'.(in_array($home,$disabled)?' style="background-color:pink" disabled':'').($home == $currentID?' selected':'').'>'.$home.'</option>';
}
foreach($surv_pick_options_v as $visitor){
echo '<option value="'.$visitor.'"'.(in_array($visitor,$disabled)?' style="background-color:pink" disabled':'').($visitor == $currentID?' selected':'').'>'.$visitor.'</option>';
}
}
echo '</select>';
}
And finally update a table with results:
$sql = "insert into " . DB_PREFIX . "picksurvivor (weekNum, userID, user, gameID, picksurv, showPicks) values (" . $_POST['week'] . ", " . $user->userID . ",'" . $user->userName . "', '" . $surv_gameID . "', '" . $_POST['survpick'] . "', ". (int)$_POST['showPicks'] . ");";
$mysqli->query($sql) or die('Error deleting survivor pick: ' . $mysqli->error);
I found a different approach, doing an update after the insert to basically brute force the gameID in there.

Order by not working, Codeigniter

ORDER BY is not working. I've tried ways I know but it won't order by, why?
returns : Call to a member function result_array() on boolean
public function getDetailbyClsandSection($class_id, $section_id, $exam_id) {
$query = $this->db->query("SELECT exam_schedules.*,subjects.name,subjects.type FROM exam_schedules,teacher_subjects,exams,class_sections,subjects WHERE exam_schedules.teacher_subject_id = teacher_subjects.id and exam_schedules.exam_id =exams.id and class_sections.id =teacher_subjects.class_section_id and teacher_subjects.subject_id=subjects.id and class_sections.class_id =" . $this->db->escape($class_id) . " and class_sections.section_id=" . $this->db->escape($section_id) . " and exam_id =" . $this->db->escape($exam_id) . " and exam_schedules.session_id=" . $this->db->escape($this->current_session));
return $query->result_array();
}
$query = $this->db->query("SELECT exam_schedules.*,subjects.name,subjects.type FROM exam_schedules,teacher_subjects,exams,class_sections,subjects WHERE exam_schedules.hide = 'N' and exam_schedules.teacher_subject_id = teacher_subjects.id and exam_schedules.exam_id =exams.id and class_sections.id =teacher_subjects.class_section_id and teacher_subjects.subject_id=subjects.id and class_sections.class_id =" . $this->db->escape($class_id) . " and class_sections.section_id=" . $this->db->escape($section_id) . " and exam_id =" . $this->db->escape($exam_id) . " and exam_schedules.session_id=" . $this->db->escape($this->current_session) . " ORDER BY exam_schedules.date_of_exam ASC");

Calculating total of rows

I fetching and displaying records from database like this
SELECT purchorders.orderno,
suppliers.suppname,
purchorders.orddate,
purchorders.deliverydate,
purchorders.initiator,
purchorders.requisitionno,
purchorders.allowprint,
purchorders.status,
suppliers.currcode,
currencies.decimalplaces AS currdecimalplaces,
SUM(purchorderdetails.unitprice*purchorderdetails.quantityord) AS ordervalue
FROM purchorders
INNER JOIN purchorderdetails
ON purchorders.orderno = purchorderdetails.orderno
INNER JOIN suppliers
ON purchorders.supplierno = suppliers.supplierid
INNER JOIN currencies
ON suppliers.currcode=currencies.currabrev
WHERE purchorders.orderno=purchorderdetails.orderno
GROUP BY purchorders.orderno,
suppliers.suppname,
purchorders.orddate,
purchorders.initiator,
purchorders.requisitionno,
purchorders.allowprint,
purchorders.status,
suppliers.currcode,
currencies.decimalplaces LIMIT 5
I am getting the result properly. But i want to calculate and display the result of ordervalues which i have displayed (total of all 5 as i limit it to 5)
I tried doing like this
$SalesOrdersResult2 = DB_query($SQL,$db);
while ($row = DB_fetch_array($SalesOrdersResult2))
{
$FormatedOrderValue2 = locale_number_format($row['ordervalue'],$row['currdecimalplaces']);
$Total = $array_sum($row['ordervalue']);
$FormatedOrderDate1 = ConvertSQLDate($row['orddate']);
$FormatedDelDate1 = ConvertSQLDate($row['deliverydate']);
echo " <tr><td> " . $row['suppname'] . " </td>";
echo " <td>$FormatedOrderDate1</td><td>$FormatedDelDate1</td><td> " . $row['initiator'] . " </td><td>$FormatedOrderValue2</td><td> " . $row['status'] . " </td></tr> ";
}
echo "<tr><td colspan='3'>Total---</td><td colspan='2'>$Total</td></tr></tbody>";
But it says "Fatal error: Function name must be a string in ..."
Somebody please help me in doing this
Thanks
I suspect you're trying to do something like this?:
$SalesOrdersResult2 = DB_query($SQL, $db);
$Total = 0;
while ($row = DB_fetch_array($SalesOrdersResult2))
{
$FormatedOrderValue2 = locale_number_format($row['ordervalue'],$row['currdecimalplaces']);
$Total += $row['ordervalue'];
$FormatedOrderDate1 = ConvertSQLDate($row['orddate']);
$FormatedDelDate1 = ConvertSQLDate($row['deliverydate']);
echo " <tr><td> " . $row['suppname'] . " </td>";
echo " <td>$FormatedOrderDate1</td><td>$FormatedDelDate1</td><td> " . $row['initiator'] . " </td><td>$FormatedOrderValue2</td><td> " . $row['status'] . " </td></tr> ";
}
echo "<tr><td colspan='3'>Total---</td><td colspan='2'>$Total</td></tr></tbody>";
Remove the $ before array_sum.

Categories