Optimize SQL queries in php file - php

I wrote PHP script to auto-update offers from provider API in my database. Unfortunately, by performing the following queries in the foreach loop (following the API records), the load is at 99% of the CPU. The script must be activated in cron every 10-15 minutes, but with this load the server is weak. How could I optimize it for more efficient work?
<?php
include "config.php";
function checkDevice($device) {
if($device == "Android" || $device == "iOS" || $device == "iPhone" || $device == "iPad") {
return true;
} else {
return false;
}
}
function countUserPayout($providerPayout) {
$summary = ($providerPayout * 100) / 2;
return ceil($summary);
}
function getOgAds() {
$response = file_get_contents("link");
$result = json_decode($response, true);
return $result["offers"];
}
function getAdGate() {
$response = file_get_contents("link");
$result = json_decode($response, true);
return $result["data"];
}
function checkOgAdsDevice($devices) {
$devicesArray = explode(",", $devices);
foreach($devicesArray as $device) {
if($device == "iPhone" || $device == "iPad" || $device == "Android") {
return true;
} else {
return false;
}
}
}
function detectDesktop($category) {
$categories = explode(",", $category);
$exists = array_search("Desktop", $categories);
if($exists) {
return true;
} else {
return false;
}
}
function createCountries($object) {
foreach($object as $country) {
$countries[] = $country;
}
if(isset($countries)) {
return $countries;
}
}
function createOfferWall() {
$offerWall = [];
foreach(getOgAds() as $offer) {
if(checkOgAdsDevice($offer["device"]) && detectDesktop($offer["device"]) == false) {
$offerWall[] = array(
"offer_id" => $offer["offerid"],
"name" => $offer["name_short"],
"requirements" => $offer["adcopy"],
"category" => $offer["device"],
"provider_payout" => $offer["payout"],
"payout" => countUserPayout($offer["payout"]),
"epc" => $offer["epc"],
"icon" => $offer["picture"],
"anchor" => $offer["link"],
"countries" => (array)$offer["country"],
"provider" => "ogads"
);
} else {
continue;
}
}
foreach(getAdGate() as $offer) {
if(checkDevice($offer["categories"][0])) {
$offerWall[] = array(
"offer_id" => $offer["id"],
"name" => $offer["adgate_rewards"]["anchor"],
"requirements" => $offer["requirements"],
"category" => $offer["categories"][0],
"provider_payout" => $offer["payout"],
"payout" => countUserPayout($offer["payout"]),
"epc" => $offer["epc"],
"icon" => $offer["creatives"]["icon"],
"anchor" => $offer["click_url"],
"countries" => createCountries($offer["countries"]),
"provider" => "adgate"
);
} else {
continue;
}
}
return $offerWall;
}
function createIdWall($dbh) {
$offerWall = createOfferWall();
foreach($offerWall as $offer) {
$idWall[$offer["offer_id"]] = $offer["offer_id"];
}
return $idWall;
}
function setCountries($dbh, $countries, $offer) {
if(isset($countries)) {
foreach($countries as $country) {
$stmt = $dbh->prepare("INSERT INTO `table`(`aaa`,`xxx`,`yyy`) VALUES(NULL, :country, :oid)");
$stmt->bindParam(":country", $country, PDO::PARAM_STR);
$stmt->bindParam(":oid", $offer, PDO::PARAM_INT);
$stmt->execute();
}
}
}
function checkOfferExists($dbh, $providerId) {
$stmt = $dbh->prepare("SELECT count(`id`) as `exists` FROM `table` WHERE `provider_id` = :providerId");
$stmt->bindParam(":providerId", $providerId, PDO::PARAM_STR);
$stmt->execute();
$result = $stmt->fetch(PDO::FETCH_ASSOC);
if($result["exists"] == 1) {
return true;
} else {
return false;
}
}
function getOfferInfo($dbh, $providerId) {
$stmt = $dbh->prepare("SELECT * FROM `table` WHERE `provider_id` = :providerId");
$stmt->bindParam(":providerId", $providerId, PDO::PARAM_STR);
$stmt->execute();
$result = $stmt->fetch(PDO::FETCH_ASSOC);
return $result;
}
function compareOffers($dbh, $providerId, $offer) {
$dbOffer = getOfferInfo($dbh, $providerId);
if($dbOffer["provider_payout"] != $offer["provider_payout"] || $dbOffer["anchor"] != $offer["anchor"] || $dbOffer["offer_name"] != $offer["name"] || $dbOffer["category"] != $offer["category"] || $dbOffer["icon"] != $offer["icon"] || $dbOffer["requirements"] != $offer["requirements"]) {
return true;
} else {
return false;
}
}
function getDbOffers($dbh) {
$stmt = $dbh->prepare("SELECT `provider_id` FROM `table`");
$stmt->execute();
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
return $result;
}
function activateOffer($dbh, $providerId) {
$stmt = $dbh->prepare("UPDATE `table` SET `active` = 1 WHERE `provider_id` = :providerId");
$stmt->bindParam(":providerId", $providerId, PDO::PARAM_INT);
$stmt->execute();
}
function disableOffer($dbh, $providerId) {
$stmt = $dbh->prepare("UPDATE `table` SET `active` = 0 WHERE `provider_id` = :providerId");
$stmt->bindParam(":providerId", $providerId, PDO::PARAM_INT);
$stmt->execute();
}
function updateOffer($dbh, $providerId, $offer) {
$stmt = $dbh->prepare("UPDATE `table` SET
`aaa` = :payout,
`bbb = :points,
`ccc` = :anchor,
`ddd` = :name,
`eee` = :category,
`fff` = :icon,
`ggg` = :requirements
WHERE `provider_id` = :providerId");
$stmt->bindParam(":providerId", $providerId, PDO::PARAM_STR);
$stmt->bindParam(":payout", $offer["provider_payout"], PDO::PARAM_INT);
$stmt->bindParam(":points", $offer["payout"], PDO::PARAM_INT);
$stmt->bindParam(":anchor", $offer["anchor"], PDO::PARAM_STR);
$stmt->bindParam(":name", $offer["name"], PDO::PARAM_STR);
$stmt->bindParam(":category", $offer["category"], PDO::PARAM_STR);
$stmt->bindParam(":icon", $offer["icon"], PDO::PARAM_STR);
$stmt->bindParam(":requirements", $offer["requirements"], PDO::PARAM_STR);
$stmt->execute();
}
function addOffer($dbh, $offer) {
$stmt = $dbh->prepare("INSERT INTO `table` (`aaa`, `bbb`, `ccc, `ddd`, `eee`, `fff`, `ggg`, `hhh`, `jjj`, `kkk`, `lll`, `zzz`, `xxx`) VALUES (NULL, :requirements, :points, :providerId, :icon, :epc, :ownPayout, :anchor, :category, :name, 1, 0, :provider);");
$stmt->bindParam(":requirements", $offer["requirements"], PDO::PARAM_STR);
$stmt->bindParam(":points", $offer["payout"], PDO::PARAM_INT);
$stmt->bindParam(":providerId", $offer["offer_id"], PDO::PARAM_INT);
$stmt->bindParam(":icon", $offer["icon"], PDO::PARAM_STR);
$stmt->bindParam(":epc", $offer["epc"], PDO::PARAM_STR);
$stmt->bindParam(":ownPayout", $offer["provider_payout"], PDO::PARAM_STR);
$stmt->bindParam(":anchor", $offer["anchor"], PDO::PARAM_STR);
$stmt->bindParam(":category", $offer["category"], PDO::PARAM_STR);
$stmt->bindParam(":name", $offer["name"], PDO::PARAM_STR);
$stmt->bindParam(":provider", $offer["provider"], PDO::PARAM_STR);
$stmt->execute();
setCountries($dbh, $offer["countries"], $offer["offer_id"]);
}
function checkStatus($dbh, $providerId) {
$stmt = $dbh->prepare("SELECT `active` FROM `table` WHERE `provider_id` = :providerId");
$stmt->bindParam(":providerId", $providerId, PDO::PARAM_INT);
$stmt->execute();
$result = $stmt->fetch(PDO::FETCH_ASSOC);
if($result["active"] == 0) {
return false;
} else {
return true;
}
}
function followOffers($dbh) {
foreach(createOfferWall() as $offer) {
if(checkOfferExists($dbh, $offer["offer_id"])) {
if(compareOffers($dbh, $offer["offer_id"], $offer)) {
updateOffer($dbh, $offer["offer_id"], $offer);
} else {
continue;
}
} else {
addOffer($dbh, $offer);
}
}
}
function findRevokeOffers($dbh) {
$idWall = array_flip(createIdWall($dbh));
foreach(getDbOffers($dbh) as $dbOffer) {
$providerId = $dbOffer["provider_id"];
if(isset($idWall[$providerId])) {
continue;
} else {
if(checkStatus($dbh, $providerId)) {
disableOffer($dbh, $providerId);
} else {
continue;
}
}
}
}
function getCurrentTime() {
$currentTime = date('Y-m-d H:i:s');
return $currentTime;
}
echo "// START [".getCurrentTime()."]" .PHP_EOL;
followOffers($dbh);
findRevokeOffers($dbh);
echo "// END" .PHP_EOL;
?>

Related

Why doesn't this work? sqlit3 php

I want to get the user by his email addresse or username ... but it doesn't work. Everytime i use a string and not a number, i just get false.
It's a school project so I can't use any frameworks :(
This doesn't work
$objAcc->getUser('email', 'example#gmail.com')
This works
$objAcc->getUser('user_id', '1')
Methode:
public function getUser($by = NULL, $value = NULL, $quantity = 0) {
global $database;
try {
$row = array();
if (isset($by) && isset($value)) {
$query = 'SELECT * FROM "user" WHERE :by=:value';
$stmt = $database->prepare($query);
$type = ($by == 'user_id' || $by == 'phone' || $by == 'fax' || $by == 'zip' || $by == 'admin') ? SQLITE3_INTEGER : SQLITE3_TEXT;
$stmt->bindValue(':by', $by, SQLITE3_TEXT);
$stmt->bindValue(':value', $value, $type);
$result = $stmt->execute();
} else {
$query = 'SELECT * FROM "user"';
$stmt = $database->prepare($query);
$result = $stmt->execute();
}
if ($quantity) {
for ($i = 0; $i < $quantity; $i++) {
$row[ $i ] = $result->fetchArray(SQLITE3_ASSOC);
}
} else {
$i = 0;
while ($entry = $result->fetchArray(SQLITE3_ASSOC)) {
$row[ $i ] = $entry;
$i++;
}
}
if (empty($row[0])) {
return FALSE;
}
return $row;
} catch (Exception $e) {
var_dump($e);
die();
}
}
I hope you can help me guys.
I don't think you can use binding for column names. I would suggest to create the SQL statement dynamically, but only after you have validated that the $by argument matches with an existing column name (avoid risk of SQL injection):
$numFields = array("user_id", "phone", "fax", "zip", "admin");
$charFields = array("email");
$allFields = array_merge($numFields, $charFields);
$row = array();
if (isset($by) && isset($value) && in_array($by, $allFields)) {
$query = 'SELECT * FROM "user" WHERE ' . $by . '=:value';
$stmt = $database->prepare($query);
$type = in_array($numFields, $by) ? SQLITE3_INTEGER : SQLITE3_TEXT;
$stmt->bindValue(':value', $value, $type);
} else {
$query = 'SELECT * FROM "user"';
$stmt = $database->prepare($query);
}
$result = $stmt->execute();

Php get_result() and fetch_assoc() alternative

I am working on writing a PHP backend program, but my program doesn't work because PHP doesn't support the get_result() and fetch_assoc() function.
How can I rewrite the code so that they can work in the same way as this function?
public function storeUser($userLoginID, $password) {
$uuid = uniqid('', true);
$hash = $this->hashSSHA($password);
$encrypted_password = $hash["encrypted"];
$salt = $hash["salt"];
$stmt = $this->conn->prepare("INSERT INTO hkcheung.users(unique_id,userLoginID,encrypted_password,salt,created_at) VALUES (?,?,?,?,NOW())");
$stmt->bind_param("ssss", $uuid, $userLoginID, $encrypted_password, $salt);
$result = $stmt->execute();
$stmt->close();
if ($result) {
$stmt = $this->conn->prepare("SELECT * FROM hkcheung.users WHERE userLoginID=?");
$stmt->bind_param("s", $userLoginID);
$stmt->execute();
$result = $stmt->get_result();
$users = $result->fetch_assoc();
$stmt->close();
return $users;
} else {
return false;
}
}
add below function to your php file
function get_result( $Statement ) {
$RESULT = array();
$Statement->store_result();
for ( $i = 0; $i < $Statement->num_rows; $i++ ) {
$Metadata = $Statement->result_metadata();
$PARAMS = array();
while ( $Field = $Metadata->fetch_field() ) {
$PARAMS[] = &$RESULT[ $i ][ $Field->name ];
}
call_user_func_array( array( $Statement, 'bind_result' ), $PARAMS );
$Statement->fetch();
}
return $RESULT;
}
and at the get_result line, change it to
$result = $this->get_result($stmt);

Get the newest data from sql but not working

I would like to get the newest comments in following code, but now only showing the oldest 50 comments, how can I edit code to showing the newest 50 comments? thanks so much
Code here:
<?php
class comments extends db_connect
{
private $requestFrom = 0;
private $language = 'en';
public function __construct($dbo = NULL)
{
parent::__construct($dbo);
}
public function allCommentsCount()
{
$stmt = $this->db->prepare("SELECT max(id) FROM comments");
$stmt->execute();
return $number_of_rows = $stmt->fetchColumn();
}
public function count($postId)
{
$stmt = $this->db->prepare("SELECT count(*) FROM comments WHERE postId = (:postId) AND removeAt = 0");
$stmt->bindParam(":postId", $postId, PDO::PARAM_INT);
$stmt->execute();
return $number_of_rows = $stmt->fetchColumn();
}
public function create($postId, $text, $notifyId = 0)
{
$result = array("error" => true,
"error_code" => ERROR_UNKNOWN);
if (strlen($text) == 0) {
return $result;
}
$post = new post($this->db);
$postInfo = $post->info($postId);
unset($post);
$currentTime = time();
$ip_addr = helper::ip_addr();
$u_agent = helper::u_agent();
$stmt = $this->db->prepare("INSERT INTO comments (fromUserId, postId, comment, createAt, notifyId, ip_addr, u_agent) value (:fromUserId, :postId, :comment, :createAt, :notifyId, :ip_addr, :u_agent)");
$stmt->bindParam(":fromUserId", $this->requestFrom, PDO::PARAM_INT);
$stmt->bindParam(":postId", $postId, PDO::PARAM_INT);
$stmt->bindParam(":comment", $text, PDO::PARAM_STR);
$stmt->bindParam(":createAt", $currentTime, PDO::PARAM_INT);
$stmt->bindParam(":notifyId", $notifyId, PDO::PARAM_INT);
$stmt->bindParam(":ip_addr", $ip_addr, PDO::PARAM_STR);
$stmt->bindParam(":u_agent", $u_agent, PDO::PARAM_STR);
if ($stmt->execute()) {
$result = array("error" => false,
"error_code" => ERROR_SUCCESS,
"commentId" => $this->db->lastInsertId(),
"comment" => $this->info($this->db->lastInsertId()));
if ($this->requestFrom != $postInfo['fromUserId']) {
$gcm = new gcm($this->db, $postInfo['fromUserId']);
$gcm->setData(GCM_NOTIFY_COMMENT, "You have a new comment.", $postId);
$gcm->send();
}
}
return $result;
}
public function remove($commentId)
{
$result = array("error" => true,
"error_code" => ERROR_UNKNOWN);
$commentInfo = $this->info($commentId);
if ($commentInfo['error'] === true) {
return $result;
}
// if ($commentInfo['fromUserId'] != $this->requestFrom) {
//
// return $result;
// }
$currentTime = time();
$stmt = $this->db->prepare("UPDATE comments SET removeAt = (:removeAt) WHERE id = (:commentId)");
$stmt->bindParam(":commentId", $commentId, PDO::PARAM_INT);
$stmt->bindParam(":removeAt", $currentTime, PDO::PARAM_INT);
if ($stmt->execute()) {
$result = array("error" => false,
"error_code" => ERROR_SUCCESS);
}
return $result;
}
public function removeAll($postId) {
$currentTime = time();
$stmt = $this->db->prepare("UPDATE comments SET removeAt = (:removeAt) WHERE postId = (:postId)");
$stmt->bindParam(":postId", $postId, PDO::PARAM_INT);
$stmt->bindParam(":removeAt", $currentTime, PDO::PARAM_INT);
}
public function info($commentId)
{
$result = array("error" => true,
"error_code" => ERROR_UNKNOWN);
$stmt = $this->db->prepare("SELECT * FROM comments WHERE id = (:commentId) LIMIT 1");
$stmt->bindParam(":commentId", $commentId, PDO::PARAM_INT);
if ($stmt->execute()) {
if ($stmt->rowCount() > 0) {
$row = $stmt->fetch();
$time = new language($this->db, $this->language);
$profile = new profile($this->db, $row['fromUserId']);
$fromUserId = $profile->get();
unset($profile);
$lowPhotoUrl = "/img/profile_default_photo.png";
if (strlen($fromUserId['lowPhotoUrl']) != 0) {
$lowPhotoUrl = $fromUserId['lowPhotoUrl'];
}
$post = new post($this->db);
$post->setRequestFrom($this->getRequestFrom());
$postInfo = $post->info($row['postId']);
$result = array("error" => false,
"error_code" => ERROR_SUCCESS,
"id" => $row['id'],
"fromUserId" => $row['fromUserId'],
"fromUserState" => $fromUserId['state'],
"fromUserUsername" => $fromUserId['username'],
"fromUserFullname" => $fromUserId['fullname'],
"fromUserPhotoUrl" => $lowPhotoUrl,
"postId" => $row['postId'],
"postFromUserId" => $postInfo['fromUserId'],
"comment" => htmlspecialchars_decode(stripslashes($row['comment'])),
"createAt" => $row['createAt'],
"notifyId" => $row['notifyId'],
"timeAgo" => $time->timeAgo($row['createAt']));
}
}
return $result;
}
public function get($postId, $commentId = 0)
{
if ($commentId == 0) {
$commentId = $this->allCommentsCount() + 1;
}
$comments = array("error" => false,
"error_code" => ERROR_SUCCESS,
"commentId" => $commentId,
"postId" => $postId,
"comments" => array());
$stmt = $this->db->prepare("SELECT id FROM comments WHERE postId = (:postId) AND id < (:commentId) AND removeAt = 0 ORDER BY id ASC LIMIT 0,38");
$stmt->bindParam(':postId', $postId, PDO::PARAM_INT);
$stmt->bindParam(':commentId', $commentId, PDO::PARAM_INT);
if ($stmt->execute()) {
while ($row = $stmt->fetch()) {
$commentInfo = $this->info($row['id']);
array_push($comments['comments'], $commentInfo);
$comments['commentId'] = $commentInfo['id'];
unset($commentInfo);
}
}
return $comments;
}
public function getPreview($postId)
{
$commentId = $this->allCommentsCount() + 1;
$comments = array("error" => false,
"error_code" => ERROR_SUCCESS,
"commentId" => $commentId,
"postId" => $postId,
"count" => $this->count($postId),
"comments" => array());
$stmt = $this->db->prepare("SELECT id FROM comments WHERE postId = (:postId) AND id < (:commentId) AND removeAt = 0 ORDER BY id ASC LIMIT 3");
$stmt->bindParam(':postId', $postId, PDO::PARAM_INT);
$stmt->bindParam(':commentId', $commentId, PDO::PARAM_INT);
if ($stmt->execute()) {
while ($row = $stmt->fetch()) {
$commentInfo = $this->info($row['id']);
array_push($comments['comments'], $commentInfo);
$comments['commentId'] = $commentInfo['id'];
unset($commentInfo);
}
}
return $comments;
}
public function setLanguage($language)
{
$this->language = $language;
}
public function getLanguage()
{
return $this->language;
}
public function setRequestFrom($requestFrom)
{
$this->requestFrom = $requestFrom;
}
public function getRequestFrom()
{
return $this->requestFrom;
}
}
Try to edit your LIMIT from LIMIT 0,38 to LIMIT 38.

Select and call_user_func_array issue

I've this function:
private function db_bind_array($stmt, &$row) {
$md = $stmt->result_metadata();
$param = array();
while($field = $md->fetch_field()) { $param[] = &$row[$field->name];}
return call_user_func_array(array($stmt, 'bind_result'), $param);
}
private function db_query($sql, $bind_param, $param) {
if($stmt = $this->conn->prepare($sql)) {
if(!$bindRet = call_user_func_array(array($stmt,'bind_param'),
array_merge(array($bind_param), $param))) $this->Terminate();
if(!$stmt->execute()) $this->Terminate();
$res = array();
if($this->db_bind_array($stmt, $res)) return array($stmt, $res);
}
}
protected function Select($recs, $table, $where, $bind_param, $param, $order_by = '', $sort = '', $limit = 1) {
if($order_by != '') $order_by = 'ORDER BY '.$order_by;
$sql = "SELECT $recs FROM $table WHERE $where $order_by $sort LIMIT $limit";
return $this->ExeSelect($sql, $bind_param, $param);
}
private function ExeSelect($sql, $bind_param, $param) {
if($res = $this->db_query($sql, $bind_param, array(&$param))) {
$stmt = $res[0]; $row = $res[1];
while($stmt->fetch()) {$this->row = $row; return $row;}
$stmt->close();
}
}
And I use it:
$row = $this->Select('id, name, title, 'Articles', where id >, 'i', 10, 'DESC', '', 10)
The problem is that it returns only one record instead of 10.
What's the problem?
Thanks
The problem is this line: while($stmt->fetch()) {$this->row = $row; return $row;}. You immediately return that result. Build an array before you return it.
private function ExeSelect($sql, $bind_param, $param) {
$ret = array();
if($res = $this->db_query($sql, $bind_param, array(&$param))) {
$stmt = $res[0]; $row = $res[1];
while($stmt->fetch()) {$ret[] = $row; }
$stmt->close();
}
return $ret;
}

Is this mysqli wrapper secure against SQL injection?

Here is how a wrapper looks like:
<?php
Class mysqliwrapper{
protected $_mysqli;
protected $_debug;
public function __construct($host, $username, $password, $database, $debug) {
$this->_mysqli = new mysqli($host, $username, $password, $database);
$this->_debug = (bool) $debug;
if (mysqli_connect_errno()) {
if ($this->_debug) {
echo mysqli_connect_error();
debug_print_backtrace();
}
return false;
}
return true;
}
public function q($query) {
if ($query = $this->_mysqli->prepare($query)) {
if (func_num_args() > 1) {
$x = func_get_args();
$args = array_merge(array(func_get_arg(1)),
array_slice($x, 2));
$args_ref = array();
foreach($args as $k => &$arg) {
$args_ref[$k] = &$arg;
}
call_user_func_array(array($query, 'bind_param'), $args_ref);
}
$query->execute();
if ($query->errno) {
if ($this->_debug) {
echo mysqli_error($this->_mysqli);
debug_print_backtrace();
}
return false;
}
if ($query->affected_rows > -1) {
return $query->affected_rows;
}
$params = array();
$meta = $query->result_metadata();
while ($field = $meta->fetch_field()) {
$params[] = &$row[$field->name];
}
call_user_func_array(array($query, 'bind_result'), $params);
$result = array();
while ($query->fetch()) {
$r = array();
foreach ($row as $key => $val) {
$r[$key] = $val;
}
$result[] = $r;
}
$query->close();
return $result;
} else {
if ($this->_debug) {
echo $this->_mysqli->error;
debug_print_backtrace();
}
return false;
}
}
public function handle() {
return $this->_mysqli;
}
}
?>
This works fine:
$w = new mysqliwrapper("localhost","root","","testdb",1);
$r = $w->q("SELECT * FROM `testdb_news` WHERE `id`=? AND `lang`=?","is",16,'en');
However, this does not:
$r = $w->q("INSERT INTO `testdb_news` ('lang','title','content','date') VALUES (?,?,?,?)","ssss","en","NewTitle","NewContent",mktime());
Why? Should I be using ?-s only for SELECT statements? And go for insert like this?
$r = $w->q("INSERT INTO `testdb_news` (lang,title,content,date) VALUES ('en','newTitle','newContent','".mktime()."')");
Is this secure? Is this class actually secure? Thanks!
safe against injections. see this question which has similar questions Parameterized Query

Categories