Very slow loop PHP - php

I'm a junior dev and i have a problem with a script's loop.
The loop cycles large array came from the DB.
The problem is complete the loop in shortest time is possible, but for now, about 500 elements it takes 15mins to finish.
It's is not acceptable.
The empty space in quotation marks is necessary for my type of file.
This is the code in private class function:
$length = count($this->fileH1);
for ($z = 0; $z < $length; $z++) {
$this->fileH2[$z]['id_paziente'] = $this->fileH1[$z]->id_paziente;
$this->fileH2[$z]['regione'] = decifra($_SESSION['cod_regione']);
$this->fileH2[$z]['asl'] = decifra($_SESSION['cod_asl']);
$this->fileH2[$z]['cod_struttura'] = decifra($_SESSION['cod_struttura']);
$this->fileH2[$z]['tipo_assist'] = "RIA";
$this->fileH2[$z]['tipo_strutt'] = decifra($_SESSION['tipo_struttura']);
// CERCO LE INFO DELLE MENOMAZIONI DEL PAZIENTE
$stmt_get_info_menomazioni = $this->centro->prepare('SELECT codice, icd9_nuovo FROM tbl_pazienti_terapie_menomazioni WHERE id_paziente = ? AND id_contratto = ? LIMIT 1');
$stmt_get_info_menomazioni->bind_param("ii", $this->fileH1[$z]->id_paziente, $this->fileH1[$z]->id_contratto); //$fileH1[$z]['id_terapia']);
$stmt_get_info_menomazioni->execute();
$stmt_get_info_menomazioni->store_result();
$stmt_get_info_menomazioni->bind_result($cod_menomazione, $icd9_menomazione);
if ($stmt_get_info_menomazioni->num_rows > 0) {
$stmt_get_info_menomazioni->fetch();
if ($cod_menomazione !== NULL || $cod_menomazione !== '')
$this->fileH2[$z]['cod_menomazione'] = $cod_menomazione;
else $this->fileH2[$z]['cod_menomazione'] = ' ';
if ($icd9_menomazione !== NULL || $icd9_menomazione !== '')
$this->fileH2[$z]['icd9_menomazione'] = str_pad($icd9_menomazione, 10, " ");
else $this->fileH2[$z]['icd9_menomazione'] = ' ';
} else {
$this->fileH2[$z]['cod_menomazione'] = ' ';
$this->fileH2[$z]['icd9_menomazione'] = ' ';
}
$stmt_get_info_menomazioni->close();
$this->fileH2[$z]['num_registro'] = $this->fileH1[$z]->anno_rif . decifra($_SESSION['cod_asl']) . '0' . date('y') . str_pad($_POST['mese'], 2, '0', STR_PAD_LEFT) . '0001';; // "203021040001"; // AGGIUNGERE numero registro struttura
$this->fileH2[$z]['medico_autorizz'] = ' ';
$this->fileH2[$z]['cod_medico_autorizz'] = ' ';
$this->fileH2[$z]['istat_primo_ricovero'] = '000000';
$this->fileH2[$z]['progressivo'] = $this->fileH1[$z]->progressivo;
// CERCO LE INFO DELLE TERAPIE DEL PAZIENTE
$stmt_get_info_menomazioni = $this->centro->prepare('SELECT data_autorizz, data_inizio, data_fine FROM tbl_pazienti_contratti WHERE id_paziente = ? AND id = ? LIMIT 1');
$stmt_get_info_menomazioni->bind_param("ii", $this->fileH1[$z]->id_paziente, $this->fileH1[$z]->id_contratto); //$fileH1[$z]['id_terapia']);
$stmt_get_info_menomazioni->execute();
$stmt_get_info_menomazioni->store_result();
$stmt_get_info_menomazioni->bind_result($data_autorizz, $data_inizio, $data_fine);
if ($stmt_get_info_menomazioni->num_rows > 0) {
$stmt_get_info_menomazioni->fetch();
if ($data_autorizz !== NULL || $data_autorizz !== '0000-00-00') $this->fileH2[$z]['data_prescrizione'] = date('dmY', strtotime($data_autorizz)); else $this->fileH2[$z]['data_prescrizione'] = ' ';
if ($data_inizio !== NULL || $data_inizio !== '0000-00-00') $this->fileH2[$z]['data_inizio_terapia'] = date('dmY', strtotime($data_inizio)); else $this->fileH2[$z]['data_inizio_terapia'] = ' ';
if ($data_fine !== NULL || $data_fine !== '0000-00-00') $this->fileH2[$z]['data_fine_terapia'] = date('dmY', strtotime($data_fine)); else $this->fileH2[$z]['data_fine_terapia'] = ' ';
// CALCOLO LE DATE DEL CICLO DI FATTURAZIONE
$data_inizio_mese_attuale = date('Y-m-1');
$data_inizio_terapia = date('Y-m-d', strtotime($data_inizio));
if ($data_inizio_mese_attuale < $data_inizio_terapia)
$this->fileH2[$z]['data_inizio_periodo_fatturazione'] = date('dmY', strtotime($data_inizio_terapia));
else $this->fileH2[$z]['data_inizio_periodo_fatturazione'] = date('dmY', strtotime($data_inizio_mese_attuale));
$data_fine_mese_attuale = date('Y-m-t'); // t = ultimo gg del mese attuale
$data_fine_terapia = date('Y-m-d', strtotime($data_fine));
if ($data_fine_mese_attuale > $data_fine_terapia)
$this->fileH2[$z]['data_fine_periodo_fatturazione'] = date('dmY', strtotime($data_fine_terapia));
else $this->fileH2[$z]['data_fine_periodo_fatturazione'] = date('dmY', strtotime($data_fine_mese_attuale));
// CALCOLO QTA PRESTAZIONI EFFETTUATE
$stmt_get_qta_prestaz_eff = $this->centro->prepare('SELECT COUNT(id) FROM tbl_pazienti_terapie_presenze WHERE MONTH(DATE(ingresso_effettuato)) = ? AND id_paziente = ?');
$stmt_get_qta_prestaz_eff->bind_param('ii', $this->mese, $this->fileH1[$z]->id_paziente);
$stmt_get_qta_prestaz_eff->execute();
$stmt_get_qta_prestaz_eff->store_result();
$stmt_get_qta_prestaz_eff->bind_result($qta_prestaz);
$stmt_get_qta_prestaz_eff->fetch();
$this->fileH2[$z]['qta_prestaz'] = str_pad($qta_prestaz, 3, "0", STR_PAD_LEFT);
$this->fileH2[$z]['codifica_nomencl'] = 't';
if ($this->fileH2[$z]['progressivo'] == '99')
$this->fileH2[$z]['codice_prestaz'] = ' ';
else $this->fileH2[$z]['codice_prestaz'] = '001.001';
$this->fileH2[$z]['esenzione_1'] = '0';
$this->fileH2[$z]['esenzione_2'] = ' ';
$this->fileH2[$z]['esenzione_3'] = '0';
$this->fileH2[$z]['onere'] = "1";
$this->fileH2[$z]['importo_compart'] = '000000,00';
$this->fileH2[$z]['posizione_compart'] = '0';
if ($this->fileH1[$z]->tariffa !== NULL || $this->fileH1[$z]->tariffa !== '')
$this->fileH2[$z]['importo_totale'] = str_replace('.', ',', str_pad(floatval($this->fileH1[$z]->tariffa) * $qta_prestaz, 9, "0", STR_PAD_LEFT));
else $this->fileH2[$z]['importo_totale'] = " ";
$stmt_get_qta_prestaz_eff->close();
}
$stmt_get_info_menomazioni->close();
$this->fileH2[$z]['posizione_contab'] = ' ';
$this->fileH2[$z]['err01'] = ' ';
$this->fileH2[$z]['err02'] = ' ';
$this->fileH2[$z]['err03'] = ' ';
$this->fileH2[$z]['err04'] = ' ';
$this->fileH2[$z]['err05'] = ' ';
$this->fileH2[$z]['err06'] = ' ';
$this->fileH2[$z]['err07'] = ' ';
$this->fileH2[$z]['err08'] = ' ';
$this->fileH2[$z]['err09'] = ' ';
$this->fileH2[$z]['err10'] = ' ';
$this->fileH2[$z]['anno_rif'] = $this->fileH1[$z]->anno_rif;
$this->fileH2[$z]['cod_strut_erog'] = decifra($_SESSION['cod_struttura_eroga']);
$this->fileH2[$z]['identificativo_mensile'] = $this->fileH1[$z]->identificativo_mensile;
$this->fileH2[$z]['anno_mese_invio'] = date('Ym');
$this->fileH2[$z]['asl_addebito'] = 000;
}
Someone can help me?
UPDATE 1:
First thanks all for the answer.
Make a unique call with JOIN and move out of loop the prepare statment. Now the time for about 500 item is 5mins.
$sql = 'SELECT COUNT(tp.id),pc.data_autorizz, pc.data_inizio, pc.data_fine, tm.codice, tm.icd9_nuovo FROM tbl_pazienti_terapie_presenze as tp LEFT JOIN tbl_pazienti_contratti as pc ON tp.id_paziente = pc.id_paziente LEFT JOIN tbl_pazienti_terapie_menomazioni as tm ON tm.id_contratto = pc.id AND tm.id_paziente = pc.id_paziente WHERE MONTH(DATE(tp.ingresso_effettuato)) = ? AND tp.id_paziente = ? AND pc.id = ?';
$do_sql = $this->centro->prepare($sql);
$length = count($this->fileH1);
for ($z = 0; $z < $length; $z++) {
$this->fileH2[$z]['id_paziente'] = $this->fileH1[$z]['id_paziente'];['id_terapia'];
$this->fileH2[$z]['regione'] = decifra($_SESSION['cod_regione']);
$this->fileH2[$z]['asl'] = decifra($_SESSION['cod_asl']);
$this->fileH2[$z]['cod_struttura'] = decifra($_SESSION['cod_struttura']);
$this->fileH2[$z]['tipo_assist'] = "RIA";
$this->fileH2[$z]['tipo_strutt'] = decifra($_SESSION['tipo_struttura']);
$do_sql->bind_param('iii', $this->mese, $this->fileH1[$z]['id_paziente'], $this->fileH1[$z]['id_contratto']);
$do_sql->execute();
$do_sql->store_result();
$do_sql->bind_result($qta_prestaz, $data_autorizz, $data_inizio, $data_fine, $cod_menomazione, $icd9_menomazione);
if ($do_sql->num_rows > 0) {
$do_sql->fetch();
if ($cod_menomazione !== NULL && $cod_menomazione !== '')
$this->fileH2[$z]['cod_menomazione'] = $cod_menomazione;
else $this->fileH2[$z]['cod_menomazione'] = ' ';
if ($icd9_menomazione !== NULL && $icd9_menomazione !== '')
$this->fileH2[$z]['icd9_menomazione'] = str_pad($icd9_menomazione, 10, " ");
else $this->fileH2[$z]['icd9_menomazione'] = ' ';
if ($data_autorizz !== NULL && $data_autorizz !== '0000-00-00') $this->fileH2[$z]['data_prescrizione'] = date('dmY', strtotime($data_autorizz)); else $this->fileH2[$z]['data_prescrizione'] = ' ';
if ($data_inizio !== NULL && $data_inizio !== '0000-00-00') $this->fileH2[$z]['data_inizio_terapia'] = date('dmY', strtotime($data_inizio)); else $this->fileH2[$z]['data_inizio_terapia'] = ' ';
if ($data_fine !== NULL && $data_fine !== '0000-00-00') $this->fileH2[$z]['data_fine_terapia'] = date('dmY', strtotime($data_fine)); else $this->fileH2[$z]['data_fine_terapia'] = ' ';
if ($this->fileH1[$z]['tariffa'] !== NULL || $this->fileH1[$z]['tariffa'] !== '')
$this->fileH2[$z]['importo_totale'] = str_replace('.', ',', str_pad(floatval($this->fileH1[$z]->tariffa) * $qta_prestaz, 9, "0", STR_PAD_LEFT));
else $this->fileH2[$z]['importo_totale'] = ' ';
$this->fileH2[$z]['codifica_nomencl'] = 't';
if ($this->fileH2[$z]['progressivo'] == '99')
$this->fileH2[$z]['codice_prestaz'] = ' ';
else $this->fileH2[$z]['codice_prestaz'] = '001.001';
$this->fileH2[$z]['esenzione_1'] = '0';
$this->fileH2[$z]['esenzione_2'] = ' ';
$this->fileH2[$z]['esenzione_3'] = '0';
$this->fileH2[$z]['onere'] = "1";
$this->fileH2[$z]['importo_compart'] = '000000,00';
$this->fileH2[$z]['posizione_compart'] = '0';
// CALCOLO LE DATE DEL CICLO DI FATTURAZIONE
$data_inizio_mese_attuale = date('Y-m-1');
$data_inizio_terapia = date('Y-m-d', strtotime($data_inizio));
if ($data_inizio_mese_attuale < $data_inizio_terapia)
$this->fileH2[$z]['data_inizio_periodo_fatturazione'] = date('dmY', strtotime($data_inizio_terapia));
else $this->fileH2[$z]['data_inizio_periodo_fatturazione'] = date('dmY', strtotime($data_inizio_mese_attuale));
$data_fine_mese_attuale = date('Y-m-t'); // t = ultimo gg del mese attuale
$data_fine_terapia = date('Y-m-d', strtotime($data_fine));
if ($data_fine_mese_attuale > $data_fine_terapia)
$this->fileH2[$z]['data_fine_periodo_fatturazione'] = date('dmY', strtotime($data_fine_terapia));
else $this->fileH2[$z]['data_fine_periodo_fatturazione'] = date('dmY', strtotime($data_fine_mese_attuale));
$this->fileH2[$z]['num_registro'] = $this->fileH1[$z]['anno_rif'] . decifra($_SESSION['cod_asl']) . '0' . date('y') . str_pad($_POST['mese'], 2, '0', STR_PAD_LEFT) . '0001';; // "203021040001"; // AGGIUNGERE numero registro struttura
$this->fileH2[$z]['medico_autorizz'] = ' ';
$this->fileH2[$z]['cod_medico_autorizz'] = ' ';
$this->fileH2[$z]['istat_primo_ricovero'] = '000000';
$this->fileH2[$z]['progressivo'] = $this->fileH1[$z]['progressivo'];
}
$this->fileH2[$z]['posizione_contab'] = ' ';
$this->fileH2[$z]['err01'] = ' ';
$this->fileH2[$z]['err02'] = ' ';
$this->fileH2[$z]['err03'] = ' ';
$this->fileH2[$z]['err04'] = ' ';
$this->fileH2[$z]['err05'] = ' ';
$this->fileH2[$z]['err06'] = ' ';
$this->fileH2[$z]['err07'] = ' ';
$this->fileH2[$z]['err08'] = ' ';
$this->fileH2[$z]['err09'] = ' ';
$this->fileH2[$z]['err10'] = ' ';
$this->fileH2[$z]['anno_rif'] = $this->fileH1[$z]['anno_rif'];
$this->fileH2[$z]['cod_strut_erog'] = decifra($_SESSION['cod_struttura_eroga']);
$this->fileH2[$z]['identificativo_mensile'] = $this->fileH1[$z]['identificativo_mensile'];
$this->fileH2[$z]['anno_mese_invio'] = date('Ym');
$this->fileH2[$z]['asl_addebito'] = 000;
$do_sql->close();
better than before but still not acceptable
UPDATE 2:
After some testing i found that this query COUNT(id) FROM tbl_pazienti_terapie_presenze WHERE MONTH(ingresso_effettuato) = ? AND id_paziente = ? causes the severe slowdown. I have no idea why this happens.
SOLUTION:
Thanks all for the answer.
The problem is the query function MONTH(). Although the field is indexed, the function MONTH() skips the index and consequently slows down the query.
Replacing it with
e.g.
WHERE ingresso_effettuato BETWEEN '2021-12-01 00:00:00', '2021-12-31 23:59:59'
or
WHERE ingresso_effettuato >= '2021-12-01 00:00:00' AND ingresso_effettuato <= '2021-12-31 23:59:59' the problem is fixed.

There are mulitple Reasons why your code might be slow.
In PHP it is often caused by misusing the Database. First of all you need setup indexes on your tables, especially for the fields which youre using for your SELECT statement.
Also since PHP have to connect to a database over a network, your code might be slower if your database is on different server than your webserver ist. Some Hosting Providers use different networks for Databases. Because of this it is crutial to make as less calls to the database as possible.
In your script i saw that you use prepare(), execute(), close() and this 3 times. Which means that you go to the database and execute some actions there. This might lead to slower performance as well.
I made a little performance test to show that there is a difference between using preapre statement within a loop and ouside:
<?php
error_reporting(E_ALL);
ini_set('display_errors','On');
$mysqli = new mysqli('db','db','db','db');
$queries = 100;
$start = microtime(true);
$resultId = null;
$resultTest = null;
for($i=0;$i<=100;$i++){
$id = 1;
$sql = "SELECT id,test FROM test WHERE id = ?";
$statement = $mysqli->prepare($sql);
$statement->bind_param('i',$id);
$statement->execute();
$statement->store_result();
$statement->bind_result($resultId,$resultTest);
$statement->close();
$id = 2;
$sql = "SELECT id,test FROM test WHERE id = ?";
$statement = $mysqli->prepare($sql);
$statement->bind_param('i',$id);
$statement->execute();
$statement->store_result();
$statement->bind_result($resultId,$resultTest);
$statement->close();
$id = 3;
$sql = "SELECT id,test FROM test WHERE id = ?";
$statement = $mysqli->prepare($sql);
$statement->bind_param('i',$id);
$statement->execute();
$statement->store_result();
$statement->bind_result($resultId,$resultTest);
$statement->close();
}
$end = microtime(true);
$diff = $end-$start;
echo "Prepare statements inside loop time: ".$diff."<br/>";
$start = microtime(true);
$sql = "SELECT id,test FROM test WHERE id = ?";
$statement1 = $mysqli->prepare($sql);
$statement2 = $mysqli->prepare($sql);
$statement3 = $mysqli->prepare($sql);
for($i=0;$i<=100;$i++){
$id = 1;
$statement1->bind_param('i',$id);
$statement1->execute();
$statement1->store_result();
$statement1->bind_result($resultId,$resultTest);
$id = 2;
$statement2->bind_param('i',$id);
$statement2->execute();
$statement2->store_result();
$statement2->bind_result($resultId,$resultTest);
$id = 3;
$statement3->bind_param('i',$id);
$statement3->execute();
$statement3->store_result();
$statement3->bind_result($resultId,$resultTest);
}
$statement1->close();
$statement2->close();
$statement3->close();
$end = microtime(true);
$diff = $end-$start;
echo "Prepare statements only execute time: ".$diff."<br/>";
Results are
Prepare statements inside loop time: 0.046118021011353
Prepare statements only execute time: 0.020095109939575
So i would suggest in first place to move your statements outside of the loop, then check your indexes.
To do so. You can write down one of your SQL Queries with Real values and execute your SELECT statement with a DESCRIBE in PHPMyadmin
e.g.
DESCRIBE SELECT COUNT(id) FROM tbl_pazienti_terapie_presenze WHERE MONTH(DATE(ingresso_effettuato)) = 12 AND id_paziente = 1336
in the Result you will see if there are indexes used or not, if not then you need to created the index for this field.
And often the SQL queries can be combined with a join since you reuse the ID in 3 differnt SQL queries the Tables must somehow to be relateable so they might be able to be joined together to one statement.
Iam not sure if this answer will fix your speed problem but at least you have some clues where you can optimize.

Related

PHP PDO Prepare select where ? Query Error

public function listeFilitreAltKategoriId($filitre,$limit,$offset) {
$sorgu = self::$db->prepare( "SELECT * FROM urun WHERE (?) LIMIT ?,?" );
$sorgu->execute(array($filitre,$limit,$offset));
return $sorgu;
}
$limit=0;
$offset=10;
$strSemt= implode(',',$semt);
$where=[];
$where[]="altkategoriid={$sorguAltMenu[ 'id' ]}";
if($strSemt!=""){
$where[]="semt IN ($strSemt)";
}
if(!empty($min) || !empty($max)){
if(!empty($min) && empty($max)){
$where[]="fiyat >= $min ";
}
if(!empty($max) && empty($min)){
$where[]="fiyat <= $max";
}
if(!empty($max) && !empty($min)){
$where[]="fiyat BETWEEN $min AND $max";
}
}
if($kur!=""){
$where[]="kur=$kur";
}
$filitre = implode(" AND ",$where);
$UrunList = ( new UrunModel() )->listeFilitreAltKategoriId($filitre,$limit,$offset);
I Use Similar to This And The Result Freezes To Zero.
This Is The Way The Query Works.
But I Wanna Make It Work Like The Master.
I know you have received a question similar to this, but I haven't solved it for 2 hours.
//$db=(new UrunModel())->database();
// $UrunList = $db->prepare( "SELECT * FROM urun WHERE ".implode(" AND ",$where)." LIMIT $limit,$offset" );
// $UrunList->execute();
$value = [
"min_limit" => $min,
"max_limit" => $max
];
$where[] = "altkategoriid = :id";
$value["id"] = $sorguAltMenu['id'];
if( !empty($min) && empty($max) ){
$where[] = "fiyat >= :min";
$value["min"] = $min;
}
if( !empty($max) && empty($min) ){
$where[] = "fiyat <= :max";
$value["max"] = $max;
}
if( !empty($max) && !empty($min) ){
$where[] = "fiyat BETWEEN :min AND :max";
$value["min"] = $min;
$value["max"] = $max;
}
if( !empty($kur) ){
$where[] = "kur = :kur";
$value["kur"] = $kur;
}
if( count($semt) ){
$place_holders = [];
$count = 1;
foreach($semt as $semt_value){
$place_holders[] = ":semt_{$count}";
$value["semt_{$count++}"] = $semt_value;
}
$place_holder_string = implode(", ", $place_holders);
$where[] = "semt IN ({$place_holder_string})";
}
$where_clause = implode(" AND ", $where);
$sql = "
SELECT *
FROM urun
WHERE {$where_clause}
LIMIT :min_limit, :max_limit
";
$query = $pdo->prepare($sql);
$query->execute($value);
while( $row = $query->fetchObject() ){
// Do something...
}

Getting same data repeatedly more than multiple times(in thousands)

I am trying to get data in table format from database with multiple queries. I am getting the exact data but the data am getting is same data repeatedly more than thousand times. Please I need a help to fix this to get actual data not multiple data below is my code. Please have a look at it. I am not getting any error but the data am getting is multiple and repeated data.
controller:
public function getReports()
{
$records = [];
$data = [];
$data['title'] = 'test Report';
$date_type = $this->input->get('filter_options');
$course = $this->input->get('course');
$filter_options = $date_type;
$department = $this->input->get('department');
$division = $this->input->get('division');
$month = 1;
$year = date('Y');
$day = date('d');
$data['department'] = $department;
$data['course'] = $course;
$data['division'] = $division;
$data['date_type'] = $date_type;
$course_condition = ' AND 1=1 ';
if($course)
$course_condition = ' AND o.title="'.$course.'"';
$department_condition = ' AND 1=1 ';
if($department)
$department_condition = ' AND u.department="'.$department.'"';
$date_condition = ' and 1=1 ';
if($date_type==1)
{
$date_condition = ' and ta.submittimestamp BETWEEN DATE_SUB(NOW(), INTERVAL 300 DAY) AND NOW() ';
//dd($date_condition);
}
else if($date_type==2)
{
$date_condition = ' and MONTH(ta.submittimestamp) = MONTH(CURRENT_DATE())
AND YEAR(ta.submittimestamp) = YEAR(CURRENT_DATE()) ';
}
else if($date_type==3)
{
$year = $this->input->get('year');
$month = $this->input->get('month');
$date_condition = ' and YEAR(ta.submittimestamp) = "'.$year.'" and MONTH(ta.submittimestamp) = "'.$month.'" ';
}
$group_condition = "GROUP by u.usr_id";
if ($course)
$users_query="SELECT o.title as course_title,u.*,u.usr_id,o.obj_id FROM object_data o,usr_data u,obj_members rn WHERE o.obj_id=rn.obj_id AND u.usr_id=rn.usr_id AND o.type='crs' AND o.obj_id=$course";
$user_records = $this->base_model->executeSelectQuery($users_query);
$final_data = [];
foreach($user_records as $user)
{
if(!$course)
continue;
$user_course_query="SELECT *, (select obj_id FROM object_reference f WHERE e.child = f.ref_id limit 1 ) as final_reference FROM object_data a , object_data g,tree c,tree e , object_reference b ,object_reference f,object_reference d WHERE a.obj_id = b.obj_id AND b.ref_id = c.parent AND c.child = d.ref_id AND d.ref_id = e.parent AND f.obj_id = g.obj_id AND a.obj_id=$course ";
$user_course_records = $this->base_model->executeSelectQuery($user_course_query);
foreach($user_course_records as $course_data)
{
$final_reference=$course_data->final_reference;
$user_tests_query = "SELECT u.firstname,o.*,ta.*,tpr.workingtime,tcr.mark_official,(tcr.reached_points/tcr.max_points)*100 as result FROM usr_data u,object_data o,tst_active ta,tst_tests tt ,tst_pass_result tpr, tst_result_cache tcr WHERE u.usr_id=ta.user_fi AND tt.obj_fi=o.obj_id AND ta.test_fi=tt.test_id AND ta.active_id=tpr.active_fi AND tcr.active_fi=ta.active_id AND u.usr_id=$user->usr_id AND o.obj_id = $final_reference ".$date_condition;
$user_tests = $this->base_model->executeSelectQuery($user_tests_query);
foreach($user_tests as $test)
{
$dta['usr_id'] = $user->usr_id;
$dta['firstname'] = $user->firstname;
$dta['email'] = $user->email;
$dta['matriculation'] = $user->matriculation;
$dta['approve_date'] = $user->approve_date;
$dta['department'] = $user->department;
$dta['tries'] = $test->tries;
$dta['test_title'] = $test->title;
$dta['submittimestamp'] = $test->submittimestamp;
$dta['workingtime'] = $test->workingtime;
// $dta['mark_official'] = $test->mark_official;
$dta['result'] = $test->result;
if($test->mark_official=='passed')
$result_status = '<span class="label label-primary"> Passed </span>';
else if($test->mark_official=='failed')
$result_status = '<span class="label label-danger"> Failed </span>';
$dta['status'] = $result_status;
$dta['division'] = $this->udfTextData(2);
$dta['job_title'] = $this->udfTextData(6);
$final_data[] = $dta;
}
}
}
$data['records'] = $final_data;

PHP Building of MySQL Query String from Passed Variables

I have a HTML search which is passing variables via $_GET to a PHP which uses these passed variables to build a query string. The problem I am facing is building a query string that may only contain one search criteria or it may contain multiple. If only one criterion is used for the search then there is no need for an "AND" statement in the query. If there are multiple criteria used then "AND" will be needed between each criteria. How can one handle this "AND" related problem?
<?php
$IKfield01 = (isset($_GET['field01']) ? $_GET['field01'] : null);
$IKfield02 = (isset($_GET['field02']) ? $_GET['field02'] : null);
$IKfield03 = (isset($_GET['field03']) ? $_GET['field03'] : null);
$IKfield04 = (isset($_GET['field04']) ? $_GET['field04'] : null);
$IKfield05 = (isset($_GET['field05']) ? $_GET['field05'] : null);
$IKfield06 = (isset($_GET['field06']) ? $_GET['field06'] : null);
$IKfield07 = (isset($_GET['field07']) ? $_GET['field07'] : null);
$IKfield08 = (isset($_GET['field08']) ? $_GET['field08'] : null);
$IKfield09 = (isset($_GET['field09']) ? $_GET['field09'] : null);
$IKfield10 = (isset($_GET['field10']) ? $_GET['field10'] : null);
$searchfield01 = mysqli_real_escape_string($mysqli,$IKfield01);
$searchfield02 = mysqli_real_escape_string($mysqli,$IKfield02);
$searchfield03 = mysqli_real_escape_string($mysqli,$IKfield03);
$searchfield04 = mysqli_real_escape_string($mysqli,$IKfield04);
$searchfield05 = mysqli_real_escape_string($mysqli,$IKfield05);
$searchfield06 = mysqli_real_escape_string($mysqli,$IKfield06);
$searchfield07 = mysqli_real_escape_string($mysqli,$IKfield07);
$searchfield08 = mysqli_real_escape_string($mysqli,$IKfield08);
$searchfield09 = mysqli_real_escape_string($mysqli,$IKfield09);
$searchfield10 = mysqli_real_escape_string($mysqli,$IKfield10);
$prequery = "SELECT * FROM table WHERE";
$prequery1 = "";
$prequery2 = "";
$prequery3 = "";
$prequery4 = "";
$prequery5 = "";
$prequery6 = "";
$prequery7 = "";
$prequery8 = "";
$prequery9 = "";
$prequery10 = "";
$prequery11 = "";
$prequery12 = " LIMIT $maxsearch";
if ($searchfield01 != '') $prequery2 = "genus LIKE '%$searchfield01%'";
if ($searchfield02 != '') $prequery3 = "AND specificEpithet LIKE '%$searchfield02%'";
if ($searchfield03 != '') $prequery4 = "AND stateProvince LIKE '%$searchfield03%'";
if ($searchfield04 != '') $prequery5 = "AND county LIKE '%$searchfield04%'";
if ($searchfield05 != '') $prequery6= "AND family LIKE '%$searchfield05%'";
if ($searchfield06 != '') $prequery7 = "AND locality LIKE '%$searchfield06%'";
if ($searchfield07 != '') $prequery8 = "AND OtherCatalogNumbers LIKE '%$searchfield07%'";
if ($searchfield08 != '') $prequery9 = "AND recordedBy LIKE '%$searchfield08%'";
if ($searchfield09 != '') $prequery10 = "AND recordNumber LIKE '$searchfield09'";
if ($searchfield10 != '') $prequery11 = "AND catalogNumber LIKE '%$searchfield10%'";
$query = "$prequery $prequery2 $prequery3 $prequery4 $prequery5 $prequery6 $prequery7 $prequery8 $prequery9 $prequery10 $prequery11 $prequery12";
$row_count = 0;
$result = mysql_query($query) or die("MS-Query Error in select-query");
$querystats=mysql_num_rows($result);
$resultcounter=1;
while ($row = mysql_fetch_array($result))
{
$IKdfield01 = "$row[field01]";
$IKdfield02 = "$row[field02]";
$IKdfield03 = "$row[field03]";
$IKdfield04 = "$row[field04]";
$IKdfield05 = "$row[field05]";
$IKdfield06 = "$row[field06]";
$IKdfield07 = "$row[field07]";
$IKdfield08 = "$row[field08]";
$IKdfield09 = "$row[field09]";
$IKdfield10 = "$row[field10]";
$IKdfield11 = "$row[field11]";
$IKdfield12 = "$row[field12]";
$IKdfield13 = "$row[field13]";
$IKdfield14 = "$row[field14]";
$IKdfield15 = "$row[field15]";
$IKdfield16 = "$row[field16]";
$IKdfield17 = "$row[field17]";
$IKdfield18 = "$row[field18]";
$IKdfield19 = "$row[field19]";
$IKdfield20 = "$row[field20]";
$IKdfield21 = "$row[field21]";
$IKdfield22 = "$row[field22]";
$IKdfield23 = "$row[field23]";
$IKdfield24 = "$row[field24]";
$IKdfield25 = "$row[field25]";
$IKdfield26 = "$row[field26]";
$IKdfield27 = "$row[field27]";
//output results
echo "$IKfield01, $IKfield02, $IKfield03, $IKfield04, $IKfield05, $IKfield06, $IKfield07, $IKfield08, $IKfield09, $IKfield10, $IKfield11, $IKfield12";
echo "$IKfield13, $IKfield14, $IKfield15, $IKfield16, $IKfield17, $IKfield18, $IKfield19, $IKfield20, $IKfield21, $IKfield22, $IKfield23, $IKfield24";
echo "$IKfield25, $IKfield26, $IKfield27, (EOR) <br>";
$resultcounter++;
$row_count++;
}
?>
You could use WHERE 1 so that you always end with and AND at every clause.
The other solution is to create a variable $where with the criteria and check if there's any content before adding clauses, if yes, you add an AND
<?php
$sql = "SELECT * FROM table"
$where = "";
// ...
if($myparam) {
if(strlen($where) > 0) $where .= ' AND';
$where .= " myparam ='myval'";
}
// ...
if(strlen($where) > 0) $sql = $sql . ' WHERE ' . $where;
I would build an array of parameters, and implode them into a query:
$query_array = array();
$fields = array(
1=>'genus',
2=>'specificEpithet',
3=>'stateProvince',
4=>'county',
5=>'family',
6=>'locality',
7=>'OtherCatalogNumbers',
8=>'recordedBy',
9=>'recordNumber',
10=>'catalogNumber'
);
for($i = 1; $i <= 10; $i++){
$field = 'field' . str_pad($i, 2, " ", STR_PAD_LEFT);
if(!isset($_GET[$field])
continue;
$value = mysqli_real_escape_string($mysqli,$_GET[$field]);
$query_array[] = $fields[$i] . ' LIKE %' . $value . '%';
}
$query = "SELECT * FROM table WHERE " . implode(' AND ', $query_array) . " LIMIT $maxsearch";
$row_count = 0;
$result = mysql_query($query) or die("MS-Query Error in select-query");
//etc

Previous/next button in PHP

I´m pretty much entirely new to PHP, so please bear with me.
I´m trying to build a website running on a cms called Core. I'm trying to make it so that the previous/next buttons cycle through tags rather than entries. Tags are stored in a database as core_tags. Each tag has it own tag_id, which is a number. I've tried changing the excisting code for thep previous/next buttons, but it keeps giving me 'Warning: mysql_fetch_array() expects parameter 1 to be resource, null given in /home/core/functions/get_entry.php on line 50'.'
Any help would be greatly appreciated.
Get_entry.php:
<?php
$b = $_SERVER['REQUEST_URI'];
if($entry) {
$b = substr($b,0,strrpos($b,"/")) . "/core/";
$id = $entry;
$isPerma = true;
} else {
$b = substr($b,0,mb_strrpos($b,"/core/")+6);
$id = $_REQUEST["id"];
}
$root = $_SERVER['DOCUMENT_ROOT'] . $b;
$http = "http://" . $_SERVER['HTTP_HOST'] . substr($b,0,strlen($b)-5);
require_once($root . "user/configuration.php");
require_once($root . "themes/".$theme."/configuration.php");
require_once($root . "functions/session.php");
if(is_numeric($id)) {
$type = "entry";
} else {
$type = "page";
}
$id = secure($id);
if($type == "page") {
$data = mysql_query("SELECT p.* FROM core_pages p WHERE p.page_title = \"$id\"");
$page_clicks = 0;
while($p = mysql_fetch_array($data)) {
$url = $p["page_url"];
$path = $root . "user/pages/" . $url;
$page_clicks = $p['hits']+1;
require($path);
}
mysql_query("UPDATE core_pages p SET
p.hits = $page_clicks
WHERE p.page_title = $id");
}
if($type == "entry") {
// queries the dbase
$data_tags = mysql_query("SELECT entry_id,entry_title FROM core_entries WHERE entry_show = 1 ORDER BY entry_position DESC") or die(mysql_error());
$navArr=array();
while($tmparray = mysql_fetch_array($data_entries,MYSQL_ASSOC)){
array_push($navArr,$tmparray['entry_id']);
}
function array_next_previous($array, $value) {
$index = array_search($value,$array);
//if user clicked to view the very first entry
if($value == reset($array)){
$return['prev'] = end($array);
$return['next'] = $array[$index + 1];
//if user clicked to view the very last entry
}else if($value == end($array)){
$return['prev'] = $array[$index - 1];
reset($array);
$return['next'] = current($array);
}else{
$return['next'] = $array[$index + 1];
$return['prev'] = $array[$index - 1];
}
return $return;
}
$data = mysql_query("SELECT e.* FROM core_entries e WHERE e.entry_id = $id AND e.entry_show = 1");
$entry_clicks = 0;
if(#mysql_num_rows($data) < 1) {
die("Invalid id, no entry to be shown");
}
while($e = mysql_fetch_array($data)) {
$nextPrevProject = array_next_previous($navArr,$id);
$entry_id = $e['entry_id'];
$entry_title = $e['entry_title'];
// DATE
$t = $e["entry_date"];
$y = substr($t,0,4);
$m = substr($t,5,2);
$d = substr($t,8,2);
$entry_date = date($date_format,mktime(0,0,0,$m,$d,$y));
$entry_text = $e['entry_text'];
$entry_extra1 = $e['entry_extra1'];
$entry_extra2 = $e['entry_extra2'];
$entry_client = $e['entry_client'];
$entry_position = $e['entry_position'];
$entry_hits = $e['hits']+1;
$entry_new = $e['entry_new'];
if($entry_new == 1) {
$isNew = true;
} else {
$isNew = false;
}
if($nice_permalinks) {
$entry_perma = "$http".$entry_id;
} else {
$entry_perma = "$http"."?entry=$entry_id";
}
$data_e2t = #mysql_query("SELECT e2t.tag_id FROM core_entry2tag e2t WHERE e2t.entry_id = $entry_id");
$tag_str = "";
while($e2t = #mysql_fetch_array($data_e2t)) {
$tag_id = $e2t["tag_id"];
$data_tags = #mysql_query("SELECT t.tag_text FROM core_tags t WHERE t.tag_id = $tag_id");
while($t = #mysql_fetch_array($data_tags)) {
$tag_text = $t["tag_text"];
$tag_str = $tag_str . "<a class=\"tag-link\" name=\"tag".$tag_id."\" href=\"#tag-"._encode($tag_text)."\">".$tag_text."</a>".$separator_tags;
}
}
$entry_tags = substr($tag_str,0,strlen($tag_str)-strlen($separator_tags));
$layout_path = $root . "user/uploads/" . treat_string($entry_title) . "/layout.php";
if(is_file($layout_path) && (#filesize($layout_path) > 0)) {
require($layout_path);
} else {
require($theme_path . "parts/entry.php");
}
}
mysql_query("UPDATE core_entries e SET
e.hits = $entry_hits
WHERE e.entry_id = $id");
}
if($isPerma) {
echo "<a class=\"index-link\" href=\"$http\">back to index</a>";
}
?>
You have not defined $data_entries, before using it here:
while($tmparray = mysql_fetch_array($data_entries,MYSQL_ASSOC)){
array_push($navArr,$tmparray['entry_id']);
}
That is why you get the very descriptive error message.
Did you mean to use $data_tags?
Use: "SELECT p.* FROM core_pages p WHERE p.page_title = '".$id."'
Note: mysql_connect is not sql-injection save. If you use mysql_connect, change to PDO.
$data_entries is not defined on line 50, then mysql_fetch_array return an exception of null value given.
Try to change $tmparray = mysql_fetch_array($data_entries,MYSQL_ASSOC) to $tmparray = mysql_fetch_array($data_tags,MYSQL_ASSOC).
Hope this help!

jqGrid integrated toolbar search not working

I am trying to get the integrated search toolbars working on my page, however I am not having any luck. The regular search function is working for me, but whenever I type anything into the integrated toolbars, it returns 0 results.
Here is my jquery:
$("#parts_table").jqGrid({
url:'testparts2.php',
datatype: "json",
colNames:['Part ID','Name', 'Description', 'Weight'],
colModel:[
{name:'part_ID',index:'part_ID', search: true, stype:'text', width:55},
{name:'part_name',index:'part_name', width:90},
{name:'part_desc',index:'part_desc', width:100},
{name:'part_weight',index:'part_weight', width:80, align:"right"},
],
rowNum:30,
rowList:[10,20,30],
pager: '#pager2',
sortname: 'part_ID',
viewrecords: true,
sortorder: "asc",
caption:"Parts in Database",
width: '800',
height: '300',
});
$("#parts_table").jqGrid('navGrid','#pager2',{edit:false,add:false,del:false});
$("#parts_table").jqGrid('filterToolbar',{stringResult: false,searchOnEnter : false, defaultSearch: 'cn', ignoreCase: true});
and here is my PHP code:
<?php
include "begin.php";
$page = $_REQUEST['page']; // get the requested page
$limit = $_REQUEST['rows']; // get how many rows we want to have into the grid
$sidx = $_REQUEST['sidx']; // get index row - i.e. user click to sort
$sord = $_REQUEST['sord']; // get the direction
if(!$sidx) $sidx =1;
//array to translate the search type
$ops = array(
'eq'=>'=', //equal
'ne'=>'<>',//not equal
'lt'=>'<', //less than
'le'=>'<=',//less than or equal
'gt'=>'>', //greater than
'ge'=>'>=',//greater than or equal
'bw'=>'LIKE', //begins with
'bn'=>'NOT LIKE', //doesn't begin with
'in'=>'LIKE', //is in
'ni'=>'NOT LIKE', //is not in
'ew'=>'LIKE', //ends with
'en'=>'NOT LIKE', //doesn't end with
'cn'=>'LIKE', // contains
'nc'=>'NOT LIKE' //doesn't contain
);
function getWhereClause($col, $oper, $val){
global $ops;
if($oper == 'bw' || $oper == 'bn') $val .= '%';
if($oper == 'ew' || $oper == 'en' ) $val = '%'.$val;
if($oper == 'cn' || $oper == 'nc' || $oper == 'in' || $oper == 'ni') $val = '%'.$val.'%';
return " WHERE $col {$ops[$oper]} '$val' ";
}
$where = ""; //if there is no search request sent by jqgrid, $where should be empty
$searchField = isset($_GET['searchField']) ? $_GET['searchField'] : false;
$searchOper = isset($_GET['searchOper']) ? $_GET['searchOper']: false;
$searchString = isset($_GET['searchString']) ? $_GET['searchString'] : false;
if ($_GET['_search'] == 'true') {
$where = getWhereClause($searchField,$searchOper,$searchString);
}
$totalrows = isset($_REQUEST['totalrows']) ? $_REQUEST['totalrows']: false;
if($totalrows) {
$limit = $totalrows;
}
$result = mysql_query("SELECT COUNT(*) AS count FROM parts");
$row = mysql_fetch_array($result,MYSQL_ASSOC);
$count = $row['count'];
if( $count >0 ) {
$total_pages = ceil($count/$limit);
} else {
$total_pages = 0;
}
if ($page > $total_pages) $page=$total_pages;
if ($limit<0) $limit = 0;
$start = $limit*$page - $limit; // do not put $limit*($page - 1)
if ($start<0) $start = 0;
$SQL = "SELECT * FROM parts ".$where." ORDER BY $sidx $sord LIMIT $start , $limit";
$result = mysql_query( $SQL ) or die("Couldn't execute query.".mysql_error());
$response->page = $page;
$response->total = $total_pages;
$response->records = $count;
$i=0;
while($row = mysql_fetch_array($result,MYSQL_ASSOC)) {
$response->rows[$i]['part_ID']=$row[part_ID];
$response->rows[$i]['cell']=array($row[part_ID],$row[part_name],$row[part_desc],$row[part_weight]);
$i++;
}
echo json_encode($response);
?>
It took me hours of searching to find a PHP example that worked for regular searching (see above), however it doesn't seem to work for the toolbar searching. Can anyone help? Thanks
edit: Here is code from jqGrid's demo folder for using this search, but it appears to be full of errors and I have no idea how to use it for my case. I don't need to specify data type for the searches (they are all varchars, so strings will work fine)..so I think that I can strip out the switch/case part for value conversion. I think I just need to change my original code to use $_REQUEST['filters'] and a foreach loop to build the query, but I'm not that great with PHP so any help is appreciated.
demo code:
$wh = "";
$searchOn = Strip($_REQUEST['_search']);
if($searchOn=='true') {
$searchstr = Strip($_REQUEST['filters']);
$wh= constructWhere($searchstr);
//echo $wh;
}
function constructWhere($s){
$qwery = "";
//['eq','ne','lt','le','gt','ge','bw','bn','in','ni','ew','en','cn','nc']
$qopers = array(
'eq'=>" = ",
'ne'=>" <> ",
'lt'=>" < ",
'le'=>" <= ",
'gt'=>" > ",
'ge'=>" >= ",
'bw'=>" LIKE ",
'bn'=>" NOT LIKE ",
'in'=>" IN ",
'ni'=>" NOT IN ",
'ew'=>" LIKE ",
'en'=>" NOT LIKE ",
'cn'=>" LIKE " ,
'nc'=>" NOT LIKE " );
if ($s) {
$jsona = json_decode($s,true);
if(is_array($jsona)){
$gopr = $jsona['groupOp'];
$rules = $jsona['rules'];
$i =0;
foreach($rules as $key=>$val) {
$field = $val['field'];
$op = $val['op'];
$v = $val['data'];
if($v && $op) {
$i++;
// ToSql in this case is absolutley needed
$v = ToSql($field,$op,$v);
if ($i == 1) $qwery = " AND ";
else $qwery .= " " .$gopr." ";
switch ($op) {
// in need other thing
case 'in' :
case 'ni' :
$qwery .= $field.$qopers[$op]." (".$v.")";
break;
default:
$qwery .= $field.$qopers[$op].$v;
}
}
}
}
}
return $qwery;
}
function ToSql ($field, $oper, $val) {
// we need here more advanced checking using the type of the field - i.e. integer, string, float
switch ($field) {
case 'id':
return intval($val);
break;
case 'amount':
case 'tax':
case 'total':
return floatval($val);
break;
default :
//mysql_real_escape_string is better
if($oper=='bw' || $oper=='bn') return "'" . addslashes($val) . "%'";
else if ($oper=='ew' || $oper=='en') return "'%" . addcslashes($val) . "'";
else if ($oper=='cn' || $oper=='nc') return "'%" . addslashes($val) . "%'";
else return "'" . addslashes($val) . "'";
}
}
$result = mysql_query("SELECT COUNT(*) AS count FROM invheader a, clients b WHERE a.client_id=b.client_id".$wh);
$row = mysql_fetch_array($result,MYSQL_ASSOC);
$count = $row['count'];
if( $count >0 ) {
$total_pages = ceil($count/$limit);
} else {
$total_pages = 0;
}
if ($page > $total_pages) $page=$total_pages;
$start = $limit*$page - $limit; // do not put $limit*($page - 1)
if ($start<0) $start = 0;
$SQL = "SELECT a.id, a.invdate, b.name, a.amount,a.tax,a.total,a.note FROM invheader a, clients b WHERE a.client_id=b.client_id".$wh." ORDER BY ".$sidx." ".$sord. " LIMIT ".$start." , ".$limit;
$result = mysql_query( $SQL ) or die("Could not execute query.".mysql_error());
$responce->page = $page;
$responce->total = $total_pages;
$responce->records = $count;
$i=0;
while($row = mysql_fetch_array($result,MYSQL_ASSOC)) {
$responce->rows[$i]['id']=$row[id];
$responce->rows[$i]['cell']=array($row[id],$row[invdate],$row[name],$row[amount],$row[tax],$row[total],$row[note]);
$i++;
}
//echo $json->encode($responce); // coment if php 5
echo json_encode($responce);
I actually just had this same problem myself yesterday. You are correct, you need to bring in the filters using $_REQUEST['filters'] and then break it up so that you can use each piece.
First, you are going to need to set stringResult: true in your jQuery file where you initialize the FilterToolbar.
Here is the code that PHP will use to bring in, and break up the filters object:
// Gets the 'filters' object from JSON
$filterResultsJSON = json_decode($_REQUEST['filters']);
// Converts the 'filters' object into a workable Array
$filterArray = get_object_vars($filterResultsJSON);
Now that you have $filterArray containing the contents of the filters object, you can now break up the rules object which is contained inside. Basically, there is another array inside the $filterArray which contains the search details if the user tries performing this search across multiple columns in their table - it's called rules.
Here is how I break up the rules object and perform a SELECT query based on the user's input:
// Begin the select statement by selecting cols from tbl
$sql = 'select '.implode(',',$crudColumns).' from '.$crudTableName;
// Init counter to 0
$counter = 0;
// Loop through the $filterArray until we process each 'rule' array inside
while($counter < count($filterArray['rules']))
{
// Convert the each 'rules' object into a workable Array
$filterRules = get_object_vars($filterArray['rules'][$counter]);
// If this is the first pass, start with the WHERE clause
if($counter == 0){
$sql .= ' WHERE ' . $filterRules['field'] . ' LIKE "%' . $filterRules['data'] . '%"';
}
// If this is the second or > pass, use AND
else {
$sql .= ' AND ' . $filterRules['field'] . ' LIKE "%' . $filterRules['data'] . '%"';
}
$counter++;
}
// Finish off the select statement
$sql .= ' ORDER BY ' . $postConfig['sortColumn'] . ' ' . $postConfig['sortOrder'];
$sql .= ' LIMIT '.$intStart.','.$intLimit;
/* run the query */
$result = mysql_query( $sql )
I'm sure you'll have questions, so feel free to ask if you do!

Categories