What started out yesterday as the beginnings of an answer for, or improvements to, code found in this question has now become something of an enigma. I cannot figure why the dynamically generated query produces different results to the equivilent when run in the mysqli client or even when written out in php as a standard prepared statement ( losing the dynamic element )
For anyone wishing to experiment I included the table schema and dummy records.
The dynamic query is built based upon existence of certain variables ( these would, in the original question, have been POST variables ) but here are static - though they can be negated by commenting them out which will in turn affect the WHERE clause that is generated.
<style>
body, body *{font-size:0.85rem;}
h1,h2{font-size:0.95rem;text-decoration:underline}
pre{white-space: pre-wrap;word-wrap: break-word;}
</style>
<?php
/*
to create a suitable table and populate with dummy data
create table `volopp` (
`id` int(10) unsigned not null auto_increment,
`taskname` varchar(50) not null default '0',
`industryname` varchar(50) not null default '0',
`country` varchar(50) not null default '0',
`orgname` varchar(50) not null default '0',
`photo` varchar(50) not null default '0',
primary key (`id`)
)
engine=innodb;
insert into `volopp` (`id`, `taskname`, `industryname`, `description`, `country`, `orgname`, `photo`, `status`) values
(1, 'squirrel juggling', 'outdoor pursuits', 'squirrels are members of the family sciuridae, a family that includes small or medium-size rodents. the squirrel family includes tree squirrels, ground squirrels, chipmunks, marmots, flying squirrels, and prairie dogs amongst other rodents.', 'scotland', 'squirrel jugglers association', 'squirrel.jpg', 1),
(2, 'hedgehog pickling', 'food and drink', 'a hedgehog is any of the spiny mammals of the subfamily erinaceinae, in the eulipotyphlan family erinaceidae. there are seventeen species of hedgehog in five genera found through parts of europe, asia, and africa, and in new zealand by introduction.', 'england', 'hog heaven association', 'hedgehog.jpg', 0),
(3, 'haggis hunting', 'outdoor pursuits', 'wild haggis is a creature of scottish folklore, said to be native to the scottish highlands. it is comically claimed to be the source of haggis, a traditional scottish dish that is in fact made from the innards of sheep.', 'scotland', 'campbell\'s haggis hunt', 'lesser-haggis.jpg', 1),
(4, 'nessie netting', 'outdoor pursuits', 'the loch ness monster or nessie is said to be a creature that inhabits loch ness in the scottish highlands. it is often described as large in size with a long neck and one or more humps protruding from the water.', 'scotland', 'nessienets.org.uk', 'loch-ness.jpg', 0),
(5, 'dwarf tossing', 'outdoor pursuits', 'dwarf-tossing, also called midget-tossing, is a pub/bar attraction in which people with dwarfism, wearing special padded clothing or velcro costumes, are thrown onto mattresses or at velcro-coated walls. participants compete to throw the person with dwarfism the farthest.', 'scotland', 'highlandgames.scot', 'highland-games.jpg', 1),
(6, 'stickleback stuffing', 'indoor pursuits', 'sticklebacks are small, elongated fishes that reach a maximum length of about 18 cm (7 inches). the members of the family are characterized by a row of 2 to 16 spines on the back, which are positioned in front of a soft-rayed dorsal fin.', 'wales', 'stickleback.org', 'spinysucker.jpg', 0),
(7, 'squirrel suckling', 'historic pastimes', 'tree rats', 'ireland', 'weirdness abounds', 'treerat.gif', 0);
For reference
+----+----------------------+-------------------+--------------------+----------+-------------------------------+--------------------+--------+
| id | taskname | industryname | description | country | orgname | photo | status |
+----+----------------------+-------------------+--------------------+----------+-------------------------------+--------------------+--------+
| 1 | squirrel juggling | outdoor pursuits | Squirrels are m... | scotland | Squirrel Jugglers Association | squirrel.jpg | 1 |
| 2 | Hedgehog Pickling | food and drink | A hedgehog is a... | england | Hog Heaven Association | hedgehog.jpg | 0 |
| 3 | Haggis Hunting | outdoor pursuits | Wild haggis is ... | scotland | Campbell's Haggis Hunt | lesser-haggis.jpg | 1 |
| 4 | Nessie Netting | outdoor pursuits | The Loch Ness M... | scotland | NessieNets.org.uk | Loch-Ness.jpg | 0 |
| 5 | Dwarf Tossing | outdoor pursuits | Dwarf-tossing, ... | scotland | highlandgames.scot | highland-games.jpg | 1 |
| 6 | Stickleback Stuffing | indoor pursuits | Sticklebacks ar... | wales | stickleback.org | spinyfucker.jpg | 0 |
| 7 | squirrel suckling | historic pastimes | tree rats... | ireland | weirdness abounds | treerat.gif | 0 |
+----+----------------------+-------------------+--------------------+----------+-------------------------------+--------------------+--------+
*/
/*
utility functions to try to assist debugging
*/
function pre( $data, $header ){
$title = $header ? sprintf( '<h1>%s</h1>', $header ) : '';
printf( '<pre>%s%s</pre>', $title, print_r($data,true) );
}
function preview_mysqli( $sql, $args ){
$index=0;
for( $i=0; $i < strlen( $sql ); $i++ ){
$char = substr( $sql, $i, 1 );
if( $char == '?' ) {
$param = $args[ $index ];
if( !strstr( $param, '"' ) )$param=sprintf( '"%s"', $param );
$sql = substr_replace( $sql, $param, $i, 1 );
$index++;
}
}
return preg_replace( '#(\t)#', ' ', $sql );
}
function varname( $var ){
foreach( $GLOBALS as $name => $value )if( $value === $var ) return $name;
return false;
}
/*
This writes out the equivilent php code one would use
to run the query manually without generating on the fly.
This produces different results but is, I'm sure, essentially
the same query being executed.
*/
function preview_mysqli_statement( $sql, $args ){
$types=array();
foreach( $args as $arg )$types[]=type( $arg );
$vars=array();
foreach( $args as $arg )$vars[]=sprintf( '$%s', varname( $arg ) );
return preg_replace('#\t#',' ',sprintf('
$sql="%s";
$stmt=$db->prepare( $sql );
$stmt->bind_param( "%s", %s );
$res=$stmt->execute();
if( $res ){
$res=$stmt->get_result();
while( $rs=$res->fetch_object() ){
pre( $rs, "-- record --" );
}
}',
$sql,
implode( '', $types ),
implode( ', ', $vars )
));
}
/*
utility to return string for the variable type
used when creating the statement binding
*/
function type($arg){
switch( gettype( $arg ) ){
case 'integer':
case 'int': return 'i';
case 'float':
case 'double': return 'd';
default: return 's';
}
}
/* standard db connection */
$dbhost = '127.0.0.1';
$dbuser = 'root';
$dbpwd = 'xxx';
$dbname = 'xxx';
$db = new mysqli( $dbhost, $dbuser, $dbpwd, $dbname );
/* parameters used to generate where clause. Comment out to negate and modify query */
$search_taskname='squirrel';
$search_industry='outdoor pursuits';
$search_country='scotland';
$search_orgname='association';
$search_description='folklore';
/* placeholders */
$where=array();
$args=array();
$types=array();
/* Clause joining verb : AND | OR */
$joiner='or';
/* create where clause conditions */
if( !empty( $search_taskname ) ){
$where[]='`taskname` like ?';
$search_taskname="%{$search_taskname}%";
$args[]=$search_taskname;
}
if( !empty( $search_industry ) ){
$where[]='`industryname`=?';
$args[]=$search_industry;
}
if( !empty( $search_country ) ){
$where[]='`country`=?';
$args[]=$search_country;
}
if( !empty( $search_orgname ) ){
$where[]='`orgname` like ?';
$search_orgname="%{$search_orgname}%";
$args[]=$search_orgname;
}
if( !empty( $search_description ) ){
$where[]='`description` like ?';
$search_description="%{$search_description}%";
$args[]=$search_description;
}
if( isset( $search_status ) ){
$where[]='`status`=?';
$args[]=$search_status;
}
if( count( $where )==0 )exit('bad foo: no "WHERE" clause parameters');
/* construct the full SQL statement with full where clauses */
$sql=sprintf('select id,taskname,industryname,country,orgname,photo,status
from `volopp`
%s;',
count( $where ) > 0 ? sprintf( 'where %s', implode( sprintf( ' %s ', $joiner ), $where ) ) : ''
);
$params=&$args;
$types=array();
foreach( $params as $param )$types[]=type( $param );
$types=implode( '', $types );
/* debug statements */
pre( preg_replace( '#\t#', ' ', $sql ), 'The generated sql statement to be passed to `prepare` method.' );
pre( preview_mysqli( $sql, $params ), 'Effective query: Can be run in mysql client' );
pre( preview_mysqli_statement( $sql, $params ), 'Generated php code to emulate the whole process. [copy]' );
$stmt=$db->prepare( $sql );
if( $stmt ){
$vars=array();
$vars[]=&$types;
foreach( $params as $param ) $vars[]=&$param;
$callback=array( $stmt, 'bind_param' );
call_user_func_array( $callback, $vars );
$result = $stmt->execute();
if( $result ){
$result=$stmt->get_result();
$i=1;
while( $rs=$result->fetch_object() ){
pre( $rs, sprintf(' --> Live record %d', $i ) );
$i++;
}
$stmt->free_result();
$stmt->close();
}
}
/*
if you copy the generated php code from debug output
and run... it should run and produce different
results.
*/
?>
The above screenshot shows 1 record returned when script is run with default parameters.
Running the generated PHP code version, as below, yields the same results as when run in the mysql client ( see above screenshot ).
<?php
$dbhost = '127.0.0.1';
$dbuser = 'root';
$dbpwd = 'xxx';
$dbname = 'xxx';
$db = new mysqli( $dbhost, $dbuser, $dbpwd, $dbname );
function pre( $data, $header ){
$title = $header ? sprintf( '<h1>%s</h1>', $header ) : '';
printf( '<pre>%s%s</pre>', $title, print_r($data,true) );
}
$search_taskname='squirrel';
$search_industry='outdoor pursuits';
$search_country='scotland';
$search_orgname='association';
$search_description='folklore';
/* clauses that use `like` */
$search_taskname="%{$search_taskname}%";
$search_orgname="%{$search_orgname}%";
$search_description="%{$search_description}%";
$sql="select id,taskname,industryname,country,orgname,photo,status
from `volopp`
where `taskname` like ? or `industryname`=? or `country`=? or `orgname` like ? or `description` like ?;";
$stmt=$db->prepare( $sql );
$stmt->bind_param( "sssss", $search_taskname, $search_industry, $search_country, $search_orgname, $search_description );
$res=$stmt->execute();
if( $res ){
$res=$stmt->get_result();
while( $rs=$res->fetch_object() ){
pre( $rs, "-- record --" );
}
}
?>
Sorry for the long post. If anyone can figure out what is going on I'd be happy to hear. No doubt I have missed something obvious and will feel stupid someone points out a glaring oops.
Your problem is in the segment...
if( $stmt ){
$vars=array();
$vars[]=&$types;
foreach( $params as $param ) $vars[]=&$param;
$callback=array( $stmt, 'bind_param' );
print_r($vars);
call_user_func_array( $callback, $vars );
The output of which is...
Array
(
[0] => sssss
[1] => %folklore%
[2] => %folklore%
[3] => %folklore%
[4] => %folklore%
[5] => %folklore%
)
To make this call easier, I would tend to use splat anyway...
if( $stmt ){
$stmt->bind_param($types, ...$params);
which gives you the output you want (I think).
I'm making a OffDayWork form, which I expect that every employee only can request their off-day-work maximum of 12 times. I use this as my reference, but it still has not worked.
This is my structure table :
- tabel_cuti
holID | holEmpId | holName |
---------------------------|
1 | 1 | Ied |
---------------------------|
2 | 3 | exp1 |
---------------------------|
3 | 4 | exp2 |
---------------------------|
4 | 1 | Married |
---------------------------|
I tried this in my model
EmployeeModel
public function HolidayRegister($data)
{
$this->db->insert('tbl_cuti',$data);
return true;
}
public function HitungCuti($data)
{
$this->db->select('count(table_cuti.holID) as countcuti');
$this->db->from('tabel_cuti');
$this->db->join('tabel_pegawai','tabel_cuti.holEmpId = tabel_pegawai.empID');
$this->db->group_by('table_cuti.holEmpId');
$totalhol = $this->db->get();
}
And my controller (Employee)
public function HolidayRegister()
{
if(!empty($_POST))
{
$data = array('holEmpId' => $this->input->post('employee_id'),
'holName' => $this->input->post('holiday_name'),
'holDate' => $this->input->post('holiday_date'),
'holDescription' => $this->input->post('description'),
'created_date' => date('Y-m-d H:i:s'),
);
$result = $this->EmployeeModel->HitungCuti($data);
if($result -> num_rows() < 12)
{
$this->EmployeeModel->HolidayRegister($data);
}
else
{
$data = array('holEmpId' => $this->input->post('employee_id'),
'holName' => $this->input->post('holiday_name'),
'holDate' => $this->input->post('holiday_date'),
'holDescription' => $this->input->post('description'),
'created_date' => date('Y-m-d H:i:s'),
);
$this->session->set_flashdata('SUCCESSMSG','Tidak ada kesempatan cuti');
$data['getEmployee'] = $this->EmployeeModel->getEmployee();
$this->load->view('holiday_register',$data);
}
}
else
{
$this->session->set_flashdata('SUCCESSMSG', "Holiday Register Successfully!!");
redirect('view-holiday');
}
}
Its my first time trying CI, so please i need your help.
On HitungCuti() method, you are counting all of the employee holiday data. You need to limit the selection only for the submitted employee data :
public function HitungCuti($data)
{
$this->db->select('holID');
$totalhol = $this->db->get_where('tabel_cuti', array('holEmpId' => $data['holEmpId'])); // only search for the specified employee ID
return $totalhol;
}
I am trying to extract data from a Wordpress database so I can get it into a new database, but having a few issues figuring things out. This is just a small sample of how some of the Wordpress tables are like.
wp_posts
id | post_type | post_status |
----------------------------------
1 | portfolio | published | ... other data
wp_postmeta
id | post_id | meta_key | meta_value |
-----------------------------------------------------------------------
1 | 1 | item_submission_title | Some title | ... other data
2 | 1 | item_technology | a:1:{i:0;s:4:"2372";} |
3 | 1 | item_description | Some description |
wp_terms
id | term_id | name |
--------------------------------
1 | 2372 | Some name | ... other data
So essentially, I have to get all id's from wp_posts where post_type is portfolio and post_status is publish.
Using these id's I then need to get the meta_value for the 3 meta_key's shown in my wp_postmeta table.
The item_technology meta_value is serialized, so I need to then unserialize it. I then need to get its id (2372) and use this to obtain further data from the wp_terms table.
There is a lot more I need to do, but achieving the above will give me the understanding of how best to do this. I have a feeling I can somehow use joins here, but not sure.
At the moment, my attempt is very ineffecient and incomplete. This is what I currently have.
$conn = Database::getInstance();
$ids = getIDs($conn);
$dataArray = array();
foreach ($ids as $row) {
$data = getData($conn, $row['id']);
$dataArray[] = $data;
}
function getIDs($conn) {
$query = "SELECT `id` FROM `wp_posts` WHERE `post_type` = \"portfolio\" and `post_status` = \"publish\"";
$sql = $conn->dbc->prepare($query);
$sql->execute();
$row = $sql->fetchAll();
return $row;
}
function getData($conn, $id) {
$query = "SELECT `meta_value` FROM `wp_postmeta` WHERE `post_id` = $id AND `meta_key` = \"item_submission_title\"";
$sql = $conn->dbc->prepare($query);
$sql->execute();
$row = $sql->fetchAll();
return $row;
}
What would be the best way to achieve what I am after?
Thanks
Considering that you have a WordPress Database, I'll assume you also have a WordPress install attached to it. If not, you should, in order to make sure you get the data you want in the manner you want without having to recreate code that deals with the multitude of WP specific "idiosyncrasies".
So the first thing you'll do is "bootstrap" WordPress so you can obtain the DB connection and all of the WordPress functionality in one east step. So let's say you create a file in the WordPress root directory...
<?php
// This includes gives us all the WordPress functionality
require_once( dirname(__FILE__) . '/wp-load.php' );
// Set parameters to gather posts
$args = array(
'posts_per_page' => -1,
'offset' => 0,
'orderby' => 'date',
'order' => 'DESC',
'post_type' => 'portfolio',
'post_status' => 'publish',
'suppress_filters' => true
);
// Retrieve matching posts
$posts_array = get_posts( $args );
// Loop through posts to get Meta values
foreach ( $posts_array as $post )
{
$item_submission_title = get_post_meta( $post->ID, 'item_submission_title', true );
$item_technology = maybe_unserialize( get_post_meta( $post->ID, 'item_technology', true ) );
$item_description = get_post_meta( $post->ID, 'item_description', true );
// Do something with this information
...
}
Of course, you might now need to get it into the other DB. WordPress can also accommodate that with a simple and powerful interface...
$otherDB = new wpdb( 'username', 'password', 'database', 'localhost' );
$table = 'other_table';
$data = array(
'item_submission_title' => $item_submission_title,
'item_technology' => $item_technology,
'item_description' => $item_description,
);
$otherDB->insert( $table, $data );
More functions of the WPDB class can be found here: https://codex.wordpress.org/Class_Reference/wpdb
in my wordpress blog i have a table consist of users and their products seperated by ";" for example :
mytable
----------------------
userid | products
----------------------
1 | camera
2 | books;keyboard;computer
3 | mouse;printer
4 | scanner
now in my script the user will add a new product so i need to check if that user has more than 3 products because in this case i will do nothing and will not add this product for him but if he has less than 3 products i need to add the new product to his products seperated by ";" something like :
$userid = 3;
$newproduct = "ball"
if (pruduct field for that user has more than 2 ";" ) {
do nothing
}else{
$wpdb->update(
'mytable',
array( 'product' => concat(product, ";", $newproduct)),
array( 'userid ' => $userid ),
array( '%s' ),
array( '%d' )
);
so the result in this example would be :
mytable
----------------------
userid | products
----------------------
1 | camera
2 | books;keyboard;computer
3 | mouse;printer;ball
4 | scanner
Despite the data normalization arguments, which are incredibly valid, if for some reason you cannot correct that and must work with what exists.
Select the products column as a string and use the PHP explode() and implode() functions. You'd end up with something like this:
$current_products = explode(';', $user['products']);
// $current_products is now an array of the user's products.
if !(count($current_products) >= 3) {
$current_products[] = $new_product;
}
$user_products = implode(';', $current_products);
// Insert $user_products into your table via UPDATE
The implode and explode functions convert strings to and from arrays based on given delimiters.
In WordPress, the right way to do this is with the user_meta table. With respect, your proposed way is not a good way.
You can set these values into the user_meta table with code like this.
$meta_key = '_my_products'; /* be sure to choose a unique key prefix */
add_user_meta( $userid, $meta_key, 'football', false );
add_user_meta( $userid, $meta_key, 'basketball', false );
You can get them back with code like this
$vals = get_user_meta( $userid, $meta_key, false );
foreach ($vals as $value) {
echo $i;
}
There are other functions for updating and deleting user_meta items. They work well. Read this. https://codex.wordpress.org/Function_Reference/get_user_meta