BAOBAB
A_CO_DB Class Reference
Inheritance diagram for A_CO_DB:
Collaboration diagram for A_CO_DB:

Public Member Functions

 _instantiate_record ( $in_db_result)
 
 __construct ( $in_pdo_object, $in_access_object)
 
 execute_query ( $in_sql, $in_parameters=NULL, $exec_only=false)
 
 get_db_backup ()
 
 get_access_class_by_id ( $in_id)
 
 can_i_see_this_record ( $in_id)
 
 get_single_raw_row_by_id ( $in_id, $and_write=false)
 
 get_single_record_by_id ( $in_id, $and_write=false)
 
 get_multiple_records_by_id ( $in_id_array, $and_write=false)
 
 get_all_readable_records ( $open_only=false, $in_this_id=NULL)
 
 get_all_writeable_records ( $in_this_id=NULL)
 
 lock_record ( $in_record_id)
 
 write_record ( $params_associative_array)
 
 delete_record ( $id)
 

Public Attributes

 $access_object
 
 $class_description
 
 $error
 
 $table_name
 

Protected Member Functions

 _create_read_security_predicate ()
 
 _create_write_security_predicate ()
 
 _create_security_predicate ( $write=false)
 

Protected Attributes

 $_pdo_object
 
 $_existing_record_objects
 

Private Member Functions

 _execute_query ( $in_sql, $in_parameters=NULL, $exec_only=false)
 

Detailed Description

This is the abstract base class for both Badger databases. The bulk of database access, and most of the security, appears in this class.

The key to security is in the two protected _predicate methods (one for read, and one for write). These analyze the logged-in user's list of IDs (using the access class' get_security_ids() method, which reloads the security item), and construct an SQL predicate for calls that prevent records from being considered that do not match the security profile. This means the records are never even read into the object from the database. They are excluded by SQL.

Definition at line 50 of file a_co_db.class.php.

Constructor & Destructor Documentation

◆ __construct()

A_CO_DB::__construct (   $in_pdo_object,
  $in_access_object 
)

The initializer

Parameters
$in_pdo_objectThis is the PDO object used to access the database. It should be initialized and connected at the time this method is called.
$in_access_objectThis is the access instance used to handle the login.

Reimplemented in CO_Security_DB, and CO_Main_Data_DB.

Definition at line 271 of file a_co_db.class.php.

273  {
274  $this->class_description = 'Abstract Base Class for Database -Should never be instantiated.';
275 
276  $this->access_object = $in_access_object;
277  $this->error = NULL;
278  $this->table_name = NULL;
279  $this->_pdo_object = $in_pdo_object;
280  if (isset($this->_pdo_object)) {
281  $this->_pdo_object->owner_instance = $this;
282  }
283  $this->_existing_record_objects = Array();
284  }

Member Function Documentation

◆ _create_read_security_predicate()

A_CO_DB::_create_read_security_predicate ( )
protected

This function creates an SQL predicate that limits the query to only those records to which the current logged-in user has read rights.

Returns
a string, containing the SQL predicate

Definition at line 104 of file a_co_db.class.php.

104  {
105  if ($this->access_object->god_mode()) { // God can do everything...
106  return '';
107  } else {
108  $access_ids = $this->access_object->get_security_ids();
109  $ret = '((read_security_id=0) OR (read_security_id IS NULL)';
110 
111  if (isset($access_ids) && is_array($access_ids) && count($access_ids)) {
112  foreach ($access_ids as $access_id) {
113  $ret .= ' OR (read_security_id='.intval($access_id).')';
114  $ret .= ' OR (write_security_id='.intval($access_id).')'; // Write security also means that we can read.
115  }
116  }
117 
118  $ret .= ')';
119 
120  // Only God can access God...
121  if (($this instanceof CO_Security_DB) && !$this->access_object->god_mode()) {
122  $ret .= ' AND (id<>'.intval(CO_Config::god_mode_id()).')';
123  }
124 
125  return $ret;
126  }
127  }

Referenced by _create_security_predicate(), CO_Security_DB\get_all_visible_logins(), CO_Main_Data_DB\get_all_visible_users(), and CO_Main_Data_DB\item_exists().

Here is the caller graph for this function:

◆ _create_security_predicate()

A_CO_DB::_create_security_predicate (   $write = false)
protected

This creates the appropriate security predicate.

Returns
a string, containing the SQL predicate
Parameters
$writeThis should be true, if we need a write predicate. Default is false.

Definition at line 167 of file a_co_db.class.php.

168  {
169 
170  $ret = $write ? $this->_create_write_security_predicate() : $this->_create_read_security_predicate();
171 
172  return $ret;
173  }
_create_read_security_predicate()
_create_write_security_predicate()

References _create_read_security_predicate(), and _create_write_security_predicate().

Referenced by CO_Main_Data_DB\_build_sql_query(), CO_Main_Data_DB\_location_predicate(), can_i_see_this_record(), delete_record(), get_access_class_by_id(), CO_Security_DB\get_all_login_objects(), CO_Security_DB\get_all_login_objects_with_access(), get_all_readable_records(), get_all_writeable_records(), get_multiple_records_by_id(), CO_Security_DB\get_multiple_records_by_login_id(), get_single_raw_row_by_id(), lock_record(), and write_record().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ _create_write_security_predicate()

A_CO_DB::_create_write_security_predicate ( )
protected

This function creates an SQL predicate that limits the query to only those records to which the current logged-in user has modification rights.

Returns
a string, containing the SQL predicate

Definition at line 135 of file a_co_db.class.php.

135  {
136  if ($this->access_object->god_mode()) { // God can do everything...
137  return '';
138  } else {
139  $access_ids = $this->access_object->get_security_ids();
140  $ret = '0';
141 
142  if (isset($access_ids) && is_array($access_ids) && count($access_ids)) {
143  $ret = '((write_security_id=0) OR (write_security_id IS NULL)';
144 
145  foreach ($access_ids as $access_id) {
146  $ret .= ' OR (write_security_id='.intval($access_id).')';
147  }
148 
149  $ret .= ')';
150 
151  // Only God can access God...
152  if (($this instanceof CO_Security_DB) && !$this->access_object->god_mode()) {
153  $ret .= ' AND (id<>'.intval(CO_Config::god_mode_id()).')';
154  }
155  }
156 
157  return $ret;
158  }
159  }

Referenced by _create_security_predicate().

Here is the caller graph for this function:

◆ _execute_query()

A_CO_DB::_execute_query (   $in_sql,
  $in_parameters = NULL,
  $exec_only = false 
)
private

This executes an SQL query, using the PDO instance. It uses PDO prepared statements to apply the query.

This is a "bottleneck" method. All access to the database needs to go through here.

Returns
any response from the database. true, if it is an "execute only" query that succeeds.
Parameters
$in_sqlThis is the SQL portion of the prepared statement.
$in_parametersThis is an array of values to be used in the prepared statement.
$exec_onlyIf true, then this means we do not expect a response. Default is false.

Definition at line 67 of file a_co_db.class.php.

70  {
71  $ret = NULL;
72  $this->error = NULL;
73  try {
74  if ($exec_only) {
75  $ret = $this->_pdo_object->preparedExec($in_sql, $in_parameters);
76  } else {
77  $ret = $this->_pdo_object->preparedQuery($in_sql, $in_parameters, false);
78  }
79  } catch (Exception $exception) {
83  $exception->getFile(),
84  $exception->getLine(),
85  $exception->getMessage());
86  $this->_security_db_object = NULL;
87  }
88 
89 // Commented out, but useful for debug.
90 // echo('SQL:<pre>'.htmlspecialchars(print_r($in_sql, true)).'</pre>');
91 // echo('Params:<pre>'.htmlspecialchars(print_r($in_parameters, true)).'</pre>');
92 // echo('RESULT:<pre>'.htmlspecialchars(print_r($ret, true)).'</pre>');
93 // echo('ERROR:<pre>'.htmlspecialchars(print_r($this->error, true)).'</pre>');
94  return $ret;
95  }
static $pdo_error_code_failed_to_open_security_db
Definition: common.inc.php:43
static $pdo_error_name_failed_to_open_security_db
Definition: en.php:35
static $pdo_error_desc_failed_to_open_security_db
Definition: en.php:36
This class provides a general error report, with file, method and error information.
Definition: error.class.php:32

References CO_Lang_Common\$pdo_error_code_failed_to_open_security_db, CO_Lang\$pdo_error_desc_failed_to_open_security_db, and CO_Lang\$pdo_error_name_failed_to_open_security_db.

Referenced by execute_query().

Here is the caller graph for this function:

◆ _instantiate_record()

A_CO_DB::_instantiate_record (   $in_db_result)

This creates a new record, based upon the class stored in the database.

Returns
a new instance of a subclass of A_CO_DB_Table_Base, loaded with its state.
Parameters
$in_db_resultThis is an associative array, with the results of the row, read from the database.

Definition at line 181 of file a_co_db.class.php.

182  {
183  $ret = NULL;
184 
185  $classname = trim($in_db_result['access_class']);
186  $id = intval($in_db_result['id']);
187 
188  if ($classname && $id) {
189  $filename = CO_Config::db_classes_class_dir().'/'.strtolower($classname).'.class.php';
190 
191  if (!class_exists($classname)) {
192  if (!file_exists($filename)) {
193  $filename = NULL;
194  $dir_array = CO_Config::db_classes_extension_class_dir();
195 
196  if (!is_array($dir_array)) {
197  $dir_array = Array($dir_array);
198  }
199 
200  foreach ($dir_array as $dir) {
201  $filename = $dir.'/'.strtolower($classname).'.class.php';
202  if (file_exists($filename)) {
203  require_once($filename);
204  break;
205  } else {
206  $filename = NULL;
207  }
208  }
209  } else {
210  require_once($filename);
211  }
212  }
213 
214  if (!$filename) {
218  $classname,
219  __LINE__,
220  __METHOD__
221  );
222  return NULL;
223  }
224 
225  if (class_exists($classname)) { // We make sure that we send references to the same object, if we instantiate it multiple times.
226  if (isset($this->_existing_record_objects[$id])) {
227  $ret = $this->_existing_record_objects[$id];
228  if (isset($ret)) { // We make sure the object jives with what was given us from the DB.
229  // This forces the collection-based classes to reload their children.
230  if (method_exists($ret, 'reload_collection')) {
231  $ret->reload_collection();
232  }
233  $ret->load_from_db($in_db_result);
234  }
235  } else {
236  $ret = new $classname($this, $in_db_result);
237  }
238 
239  if (!$ret) {
243  $classname,
244  __LINE__,
245  __METHOD__
246  );
247  return NULL;
248  }
249 
250  // Make sure we cache this for later.
251  $this->_existing_record_objects[$id] = $ret;
252  } else {
256  $classname,
257  __LINE__,
258  __METHOD__
259  );
260  }
261  }
262 
263  return $ret;
264  }
static $db_error_code_class_file_not_found
Definition: common.inc.php:49
static $db_error_code_class_not_created
Definition: common.inc.php:50
static $db_error_name_class_file_not_found
Definition: en.php:50
static $db_error_desc_class_not_created
Definition: en.php:53
static $db_error_desc_class_file_not_found
Definition: en.php:51
static $db_error_name_class_not_created
Definition: en.php:52

References CO_Lang_Common\$db_error_code_class_file_not_found, CO_Lang_Common\$db_error_code_class_not_created, CO_Lang\$db_error_desc_class_file_not_found, CO_Lang\$db_error_desc_class_not_created, CO_Lang\$db_error_name_class_file_not_found, and CO_Lang\$db_error_name_class_not_created.

Referenced by CO_Main_Data_DB\generic_search(), CO_Security_DB\get_all_login_objects(), CO_Security_DB\get_all_login_objects_with_access(), get_all_readable_records(), get_all_writeable_records(), CO_Security_DB\get_credentials_by_api_key(), CO_Security_DB\get_initial_record_by_id(), CO_Security_DB\get_initial_record_by_login_id(), get_multiple_records_by_id(), and CO_Security_DB\get_multiple_records_by_login_id().

Here is the caller graph for this function:

◆ can_i_see_this_record()

A_CO_DB::can_i_see_this_record (   $in_id)

This returns true, if the current user at least has read access to the record whose ID is provided..

This is "security safe," so that means that if the user does not have rights to the row, or the row does not exist, they will get false.

Returns
a boolean, true, if the user has read access to an existing record in this database.
Parameters
$in_idThis is the ID of the record to check.

Definition at line 358 of file a_co_db.class.php.

359  {
360  $ret = false;
361 
362  if (intval($in_id)) {
363  $predicate = $this->_create_security_predicate();
364 
365  if ($predicate) {
366  $predicate .= ' AND ';
367  } else {
368  $predicate = 'true AND ';
369  }
370 
371  $sql = 'SELECT id FROM '.$this->table_name.' WHERE '.$predicate.'id='.intval($in_id);
372 
373  $ret = $this->execute_query($sql, Array());
374 
375  if (isset($ret) && is_array($ret) && count($ret)) {
376  $ret = intval($ret[0]['id']) == intval($in_id);
377  }
378  }
379 
380  return $ret;
381  }
execute_query( $in_sql, $in_parameters=NULL, $exec_only=false)
_create_security_predicate( $write=false)

References _create_security_predicate(), and execute_query().

Here is the call graph for this function:

◆ delete_record()

A_CO_DB::delete_record (   $id)

This deletes a record, based on its unique ID in the table. The logged-in user must have write permission for the record.

This double-checks after the delete, just to make sure the record was, indeed, deleted.

This is properly "screened" for security.

Returns
true if the deletion was successful.

Definition at line 750 of file a_co_db.class.php.

751  {
752  $ret = false;
753 
754  $id = intval($id);
755  $predicate = $this->_create_security_predicate(true);
756 
757  if ($predicate) {
758  $predicate .= ' AND ';
759  }
760 
761  // First, make sure we have write permission for this record, and that the record exists.
762  $sql = 'SELECT id FROM '.$this->table_name.' WHERE ('.$predicate.'id='.$id.')';
763  $temp = $this->execute_query($sql);
764 
765  if (!$this->error && isset($temp) && $temp && is_array($temp) && (1 == count($temp))) {
766  $sql = 'DELETE FROM '.$this->table_name.' WHERE ('.$predicate.'id='.$id.')';
767  $temp = $this->execute_query($sql, Array(), true); // We call this as an "execute-only" query.
768  if (!$temp || $this->error) {
772  } else {
773  // Make sure she's dead, Jim. We do an open-ended check.
774  $sql = 'SELECT id FROM '.$this->table_name.' WHERE id='.$id;
775  $temp = $this->execute_query($sql);
776  if (!$this->error && isset($temp) && is_array($temp) && (0 == count($temp))) {
777  // Make sure that we also remove it from our cache.
778  if (isset($this->_existing_record_objects[$id])) {
779  $this->_existing_record_objects[$id]->danger_will_robinson_danger_clear_id();
780  unset($this->_existing_record_objects[$id]);
781  }
782 
783  $ret = true;
784  } else {
788  }
789  }
790  } else {
794  }
795 
796  return $ret;
797  }
static $pdo_error_code_failed_delete_attempt
Definition: common.inc.php:47
static $pdo_error_code_illegal_delete_attempt
Definition: common.inc.php:46
static $pdo_error_desc_illegal_delete_attempt
Definition: en.php:45
static $pdo_error_name_illegal_delete_attempt
Definition: en.php:44
static $pdo_error_desc_failed_delete_attempt
Definition: en.php:48
static $pdo_error_name_failed_delete_attempt
Definition: en.php:47

References CO_Lang_Common\$pdo_error_code_failed_delete_attempt, CO_Lang_Common\$pdo_error_code_illegal_delete_attempt, CO_Lang\$pdo_error_desc_failed_delete_attempt, CO_Lang\$pdo_error_desc_illegal_delete_attempt, CO_Lang\$pdo_error_name_failed_delete_attempt, CO_Lang\$pdo_error_name_illegal_delete_attempt, _create_security_predicate(), and execute_query().

Here is the call graph for this function:

◆ execute_query()

A_CO_DB::execute_query (   $in_sql,
  $in_parameters = NULL,
  $exec_only = false 
)

This is an accessor for the query execution method.

Returns
any response from the database.
Parameters
$in_sqlThis is the SQL portion of the prepared statement.
$in_parametersThis is an array of values to be used in the prepared statement.
$exec_onlyIf true, then this means we do not expect a response. Default is false.

Definition at line 292 of file a_co_db.class.php.

295  {
296  return $this->_execute_query($in_sql, $in_parameters, $exec_only);
297  }
_execute_query( $in_sql, $in_parameters=NULL, $exec_only=false)

References _execute_query().

Referenced by CO_Security_DB\add_personal_token_from_current_login(), can_i_see_this_record(), CO_Security_DB\count_all_login_objects_with_access(), delete_record(), CO_Main_Data_DB\generic_search(), get_access_class_by_id(), CO_Security_DB\get_all_login_ids(), CO_Security_DB\get_all_login_objects(), CO_Security_DB\get_all_login_objects_with_access(), CO_Security_DB\get_all_personal_ids_except_for_id(), get_all_readable_records(), CO_Security_DB\get_all_tokens(), CO_Security_DB\get_all_user_objects_with_access(), CO_Security_DB\get_all_visible_logins(), CO_Main_Data_DB\get_all_visible_users(), get_all_writeable_records(), CO_Security_DB\get_credentials_by_api_key(), get_db_backup(), CO_Security_DB\get_initial_record_by_id(), CO_Security_DB\get_initial_record_by_login_id(), CO_Security_DB\get_logins_that_have_any_of_my_ids(), CO_Security_DB\get_logins_with_personal_ids(), get_multiple_records_by_id(), CO_Security_DB\get_multiple_records_by_login_id(), CO_Security_DB\get_personal_ids_for_id(), CO_Security_DB\get_security_ids_for_id(), get_single_raw_row_by_id(), CO_Security_DB\i_have_all_ids(), CO_Main_Data_DB\item_exists(), lock_record(), CO_Security_DB\remove_personal_token_from_this_login(), and write_record().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_access_class_by_id()

A_CO_DB::get_access_class_by_id (   $in_id)

This returns the access class for the given ID.

This is "security safe," so that means that if the user does not have rights to the row, they will get NULL.

Returns
a string, containing the access_class data column. NULL, if no response (like the ID does not exist, or the user does not have read rights to it).
Parameters
$in_idThis is the ID of the record to fetch.

Definition at line 327 of file a_co_db.class.php.

328  {
329  $ret = NULL;
330 
331  $predicate = $this->_create_security_predicate();
332 
333  if ($predicate) {
334  $predicate .= ' AND ';
335  } else {
336  $predicate = 'true AND ';
337  }
338 
339  $sql = 'SELECT access_class FROM '.$this->table_name.' WHERE '.$predicate.'id='.intval($in_id);
340 
341  $ret = $this->execute_query($sql, Array());
342 
343  if (isset($ret) && is_array($ret) && count($ret)) {
344  $ret = strval($ret[0]['access_class']);
345  }
346 
347  return $ret;
348  }

References _create_security_predicate(), and execute_query().

Here is the call graph for this function:

◆ get_all_readable_records()

A_CO_DB::get_all_readable_records (   $open_only = false,
  $in_this_id = NULL 
)

This returns instances of every readable record in the database readable by the logged-in user (or only "open" records, if no login).

This is properly "screened" for security.

Returns
an array, containing one or more instances of a subclass of A_CO_DB_Table_Base (Each instance may be a different class)
Parameters
$open_onlyIf true, then we will look for ONLY records with a NULL or 0 read_security_id, even if we are logged in.
$in_this_idIf we are in "god mode," we can look for particular IDs.

Definition at line 502 of file a_co_db.class.php.

504  {
505  $ret = NULL;
506 
507  $predicate = $open_only ? '((read_security_id=0) OR (read_security_id IS NULL))' : $this->_create_security_predicate();
508 
509  // No need for an AND, as the predicate is the only qualifier.
510  if (!$predicate) {
511  $in_this_id = intval($in_this_id);
512  if ($in_this_id) { // We can look for certain IDs in God Mode.
513  $predicate = "(read_security_id=$in_this_id)";
514 
515  } else {
516  $predicate = 'true'; // If we are in "God Mode," we could get no predicate, so we just go with "1".
517  }
518  }
519 
520  $sql = 'SELECT * FROM '.$this->table_name.' WHERE '.$predicate;
521  $temp = $this->execute_query($sql, Array());
522  if (isset($temp) && $temp && is_array($temp) && count($temp) ) {
523  $ret = Array();
524  foreach ($temp as $result) {
525  if (isset($result) && is_array($result) && count($result)) {
526  $result = $this->_instantiate_record($result);
527  // Belt and suspenders. Make sure nothing leaks through.
528  if ($result && $result->user_can_read()) {
529  array_push($ret, $result);
530  }
531  }
532  }
533  usort($ret, function($a, $b){return ($a->id() > $b->id());});
534  }
535 
536  return $ret;
537  }
_instantiate_record( $in_db_result)

References _create_security_predicate(), _instantiate_record(), and execute_query().

Here is the call graph for this function:

◆ get_all_writeable_records()

A_CO_DB::get_all_writeable_records (   $in_this_id = NULL)

This returns instances of every writeable record in the database readable by the logged-in user (cannot be used by non-logged-in-users).

This is properly "screened" for security.

Returns
an array, containing one or more instances of a subclass of A_CO_DB_Table_Base (Each instance may be a different class)
Parameters
$in_this_idIf we are in "god mode," we can look for particular IDs.

Definition at line 547 of file a_co_db.class.php.

548  {
549  $ret = NULL;
550 
551  $access_ids = $this->access_object->get_security_ids();
552 
553  // Only logged-in users can write.
554  if (isset($access_ids) && is_array($access_ids) && count($access_ids)) {
555  $predicate = $this->_create_security_predicate(true);
556 
557  // No need for an AND, as the predicate is the only qualifier.
558  if (!$predicate) {
559  $in_this_id = intval($in_this_id);
560  if ($in_this_id) { // We can look for certain IDs in God Mode.
561  $predicate = "(write_security_id=$in_this_id)";
562 
563  } else {
564  $predicate = 'true'; // If we are in "God Mode," we could get no predicate, so we just go with "1".
565  }
566  }
567 
568  $sql = 'SELECT * FROM '.$this->table_name.' WHERE '.$predicate;
569  $temp = $this->execute_query($sql, Array());
570  if (isset($temp) && $temp && is_array($temp) && count($temp) ) {
571  $ret = Array();
572  foreach ($temp as $result) {
573  $result = $this->_instantiate_record($result);
574  // Belt and suspenders. Make sure nothing leaks through.
575  if ($result && $result->user_can_write()) {
576  array_push($ret, $result);
577  }
578  }
579  usort($ret, function($a, $b){return ($a->id() > $b->id());});
580  }
581  }
582 
583  return $ret;
584  }

References _create_security_predicate(), _instantiate_record(), and execute_query().

Here is the call graph for this function:

◆ get_db_backup()

A_CO_DB::get_db_backup ( )

This is a special "God Mode-Only" method that dumps the entire table. It is used to generate a CSV backup file.

The user must be logged in as "God."

Returns
an array of associative arrays, with the dump. NULL if the user is not authorized.

Definition at line 307 of file a_co_db.class.php.

307  {
308  $ret = NULL;
309 
310  if ($this->access_object->god_mode()) {
311  $sql = 'SELECT * FROM '.$this->table_name.' WHERE id>1 ORDER BY id';
312 
313  $ret = $this->execute_query($sql, Array());
314  }
315 
316  return $ret;
317  }

References execute_query().

Here is the call graph for this function:

◆ get_multiple_records_by_id()

A_CO_DB::get_multiple_records_by_id (   $in_id_array,
  $and_write = false 
)

This function returns one or more record instances, by their unique IDs in the table.

This is properly "screened" for security.

Returns
an array, containing one or more instances of a subclass of A_CO_DB_Table_Base (Each instance may be a different class)
Parameters
$in_id_arrayThis is an array of integers, each of which is the ID of a record to fetch.
$and_writeIf this is true, then we need modify permission for the record.

Definition at line 444 of file a_co_db.class.php.

446  {
447  $ret = NULL;
448 
449  $predicate = $this->_create_security_predicate($and_write);
450 
451  if ($predicate) { // If we got a predicate, then we AND it with the rest of the statement.
452  $predicate .= ' AND ';
453  }
454 
455  $sql = 'SELECT * FROM '.$this->table_name.' WHERE '.$predicate.'(';
456  $params = Array();
457  // Clean the array to make sure they are all integers.
458  $id_array = array_map('intval', $in_id_array);
459  foreach ($id_array as $id) {
460  if (0 < $id) {
461  if (0 < count($params)) {
462  $sql .= ' OR ';
463  }
464  $sql.= '(id=?)';
465  array_push($params, $id);
466  }
467  }
468 
469  $sql .= ')';
470 
471  $temp = $this->execute_query($sql, $params);
472 // Commented out, but useful for debug.
473 // echo('SQL:<pre>'.htmlspecialchars(print_r($sql, true)).'</pre>');
474 // echo('PARAMS:<pre>'.htmlspecialchars(print_r($params, true)).'</pre>');
475 // echo('RESPONSE:<pre>'.htmlspecialchars(print_r($temp, true)).'</pre>');
476  if (isset($temp) && $temp && is_array($temp) && count($temp) ) {
477  $ret = Array();
478  foreach ($temp as $result) {
479  $result = $this->_instantiate_record($result);
480  if (isset($result) && ($result instanceof A_CO_DB_Table_Base)) {
481  $weregood = $and_write ? $result->user_can_write() : $result->user_can_read();
482  // Belt and suspenders. Make sure nothing leaks through.
483  if ($weregood) {
484  $ret[] = $result;
485  }
486  }
487  }
488  usort($ret, function($a, $b){return ($a->id() > $b->id());});
489  }
490 
491  return $ret;
492  }

References _create_security_predicate(), _instantiate_record(), and execute_query().

Referenced by get_single_record_by_id().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_single_raw_row_by_id()

A_CO_DB::get_single_raw_row_by_id (   $in_id,
  $and_write = false 
)

This is a special method that does not apply a security predicate. It is used to force-reload record instances.

This should ONLY be called from the database reloader functions.

Returns
an associative array, containing the "raw" database record response.
Parameters
$in_idThis is the ID of the record to fetch.
$and_writeIf this is true, then we need modify permission for the record.

Definition at line 391 of file a_co_db.class.php.

393  {
394  $ret = NULL;
395 
396  $predicate = $this->_create_security_predicate($and_write);
397 
398  if ($predicate) {
399  $predicate .= ' AND ';
400  } else {
401  $predicate = 'true AND ';
402  }
403 
404  $sql = 'SELECT * FROM '.$this->table_name.' WHERE '.$predicate.'id='.intval($in_id);
405 
406  $ret = $this->execute_query($sql, Array());
407 
408  if (isset($ret) && is_array($ret) && count($ret)) {
409  $ret = $ret[0];
410  }
411  return $ret;
412  }

References _create_security_predicate(), and execute_query().

Here is the call graph for this function:

◆ get_single_record_by_id()

A_CO_DB::get_single_record_by_id (   $in_id,
  $and_write = false 
)

This function returns a single record instance, by its unique ID in the table.

This is properly "screened" for security.

Returns
a single instance of a subclass of A_CO_DB_Table_Base
Parameters
$in_idThis is the ID of the record to fetch.
$and_writeIf this is true, then we need modify permission for the record.

Definition at line 422 of file a_co_db.class.php.

424  {
425  $ret = NULL;
426 
427  $temp = $this->get_multiple_records_by_id(Array($in_id), $and_write);
428 
429  if (isset($temp) && $temp && is_array($temp) && count($temp) ) {
430  $ret = $temp[0];
431  }
432 
433  return $ret;
434  }
get_multiple_records_by_id( $in_id_array, $and_write=false)

References get_multiple_records_by_id().

Here is the call graph for this function:

◆ lock_record()

A_CO_DB::lock_record (   $in_record_id)

This "locks" a given record by setting its read_security_id to -2.

Returns
an integer; the previous contents of the read_security_id column.
Parameters
$in_record_idThis is the unique ID of the record to be "locked."

Definition at line 592 of file a_co_db.class.php.

593  {
594  $ret = 0;
595 
596  $predicate = $this->_create_security_predicate(true);
597 
598  if ($predicate) {
599  $predicate .= ' AND ';
600  }
601 
602  $in_record_id = intval($in_record_id); // Make sure we are an integer.
603 
604  if (0 < $in_record_id) {
605  // First, we look for a record with our ID, and for which we have write permission, and we get the original Read ID.
606  $sql = 'SELECT read_security_id FROM '.$this->table_name.' WHERE '.$predicate.'id='.$in_record_id;
607 
608  $temp = $this->execute_query($sql, Array());
609 
610  if (isset($temp) && $temp && is_array($temp) && (1 == count($temp)) ) { // If we got a record, then we'll be updating it.
611  $ret = intval($temp[0]); // Get the original value.
612 
613  $sql = 'UPDATE '.$this->table_name.' SET read_security_id=-2 WHERE id=?';
614 
615  $temp = $this->execute_query($sql, Array($in_record_id));
616 
617  if ($this->error) { // If we had an error, we return squat.
618  $ret = 0;
619  }
620  }
621  }
622 
623  return $ret;
624  }

References _create_security_predicate(), and execute_query().

Here is the call graph for this function:

◆ write_record()

A_CO_DB::write_record (   $params_associative_array)

This updates or creates a database record (row), based on an associative array of parameters passed in.

If the 'id' column is 0 or NULL, then this will be a new record.

This is properly "screened" for security.

Returns
true (Successful update), or the integer ID of a new record.
Parameters
$params_associative_arrayThis is an associative array of parameters, where the key is the database column name.

Definition at line 636 of file a_co_db.class.php.

637  {
638  $ret = false;
639  if (isset($params_associative_array) && is_array($params_associative_array) && count($params_associative_array)) {
640  $access_ids = $this->access_object->get_security_ids();
641  $params_associative_array['last_access'] = date('Y-m-d H:i:s');
642  if (isset($access_ids) && is_array($access_ids) && count($access_ids)) {
643  $predicate = $this->_create_security_predicate(true);
644 
645  if ($predicate) {
646  $predicate .= ' AND ';
647  }
648 
649  $id = isset($params_associative_array['id']) ? intval($params_associative_array['id']) : 0; // We extract the ID from the fields, or assume a new record.
650 
651  if (0 < $id) {
652  // First, we look for a record with our ID, and for which we have write permission.
653  $sql = 'SELECT * FROM '.$this->table_name.' WHERE '.$predicate.'id='.$id;
654 
655  $temp = $this->execute_query($sql, Array());
656 
657  if (isset($temp) && $temp && is_array($temp) && (1 == count($temp)) ) { // If we got a record, then we'll be updating it.
658  $sql = 'UPDATE '.$this->table_name.'';
659  if (!CO_Config::use_personal_tokens()) {
660  unset($params_associative_array['personal_ids']); // We do not change the personal ID column, if we don't have it enabled.
661  }
662 
663  unset($params_associative_array['id']); // We remove the ID parameter. That can't be changed.
664 
665  $params = array_values($params_associative_array);
666  $keys = array_keys($params_associative_array);
667  $set_sql = ''.implode('=?,', $keys).'=?';
668 
669  $sql .= ' SET '.$set_sql.' WHERE ('.$predicate.'id='.$id.')';
670  $this->execute_query($sql, $params, true);
671  if (!$this->error) { // Make sure that we update the access time on cached objects.
672  if (isset($this->_existing_record_objects[$id])) {
673  $this->_existing_record_objects[$id]->last_access = strtotime($params_associative_array['last_access']);
674  }
675  $ret = true;
676  }
677  } else {
678  $sql = 'SELECT * FROM '.$this->table_name.' WHERE id='.$id; // Look for a record with the proposed ID (assume we don't have permission).
679 
680  $temp = $this->execute_query($sql, Array());
681 
682  if (isset($temp) && $temp && is_array($temp) && count($temp)) { // If we got a record, then we're aborting, as we tried to change an existing rcord.
686  }
687  }
688  } else {
689  $sql = 'SELECT * FROM '.$this->table_name.' WHERE id=1'; // We simply get the template.
690 
691  $temp = $this->execute_query($sql, Array());
692 
693  if (isset($temp) && $temp && is_array($temp) && count($temp) ) {
694  $sql = 'INSERT INTO '.$this->table_name.'';
695  if (!CO_Config::use_personal_tokens()) {
696  unset($params_associative_array['personal_ids']); // We do not change the personal ID column, if we don't have it enabled.
697  }
698  unset($params_associative_array['id']);
699 
700  // If there is no read ID specified, it becomes public.
701  if (!isset($params_associative_array['read_security_id'])) {
702  $params_associative_array['read_security_id'] = 0;
703  }
704 
705  // If there is no write ID specified, then we simply take the first one off the list.
706  if (!isset($params_associative_array['write_security_id']) && isset($access_ids[1])) {
707  $params_associative_array['write_security_id'] = $access_ids[1];
708  }
709 
710  foreach ($params_associative_array as $key => $value) {
711  if (isset($temp[$key])) {
712  $temp[$key] = isset($value) ? $value : NULL;
713  }
714  }
715 
716  $keys = array_keys($params_associative_array);
717 
718  $keys_sql = '('.implode(',', $keys).')';
719  $values_sql = '('.implode(',', array_map(function($in){return '?';}, $keys)).') RETURNING id;';
720 
721  $sql .= " $keys_sql VALUES $values_sql";
722  $this->execute_query($sql, array_values($params_associative_array), true);
723 
724  if (!$this->error) {
725  // Get the ID of the new row we just created.
726  $ret = $this->_pdo_object->last_insert;
727  }
728  } else {
732  }
733  }
734  }
735  }
736 
737  return $ret;
738  }
static $pdo_error_code_illegal_write_attempt
Definition: common.inc.php:45
static $pdo_error_desc_illegal_write_attempt
Definition: en.php:42
static $pdo_error_name_illegal_write_attempt
Definition: en.php:41

References CO_Lang_Common\$pdo_error_code_illegal_write_attempt, CO_Lang\$pdo_error_desc_illegal_write_attempt, CO_Lang\$pdo_error_name_illegal_write_attempt, _create_security_predicate(), and execute_query().

Here is the call graph for this function:

Member Data Documentation

◆ $_existing_record_objects

A_CO_DB::$_existing_record_objects
protected

Definition at line 52 of file a_co_db.class.php.

◆ $_pdo_object

A_CO_DB::$_pdo_object
protected

Definition at line 51 of file a_co_db.class.php.

◆ $access_object

A_CO_DB::$access_object

Definition at line 53 of file a_co_db.class.php.

Referenced by CO_Security_DB\get_all_user_objects_with_access().

◆ $class_description

A_CO_DB::$class_description

Definition at line 54 of file a_co_db.class.php.

◆ $error

A_CO_DB::$error

Definition at line 55 of file a_co_db.class.php.

◆ $table_name

A_CO_DB::$table_name

Definition at line 56 of file a_co_db.class.php.