Subversion Repositories php_users

Rev

Rev 10 | Rev 17 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 10 Rev 16
Line 63... Line 63...
63
 */
63
 */
64
 
64
 
65
class usersDataSource {
65
class usersDataSource {
66
   
66
   
67
   /**
67
   /**
68
    * @var string[] $dbDefinition Contains the configuration for the class
68
    * @var string[] $configuration Contains the configuration for the class
69
    * 
69
    * 
70
    * May be modified by the calling program. Must be replicated in userDataSource class
70
    * May be modified by the calling program. Must be replicated in userDataSource class
71
    */
71
    */
72
   private $dbDefinition = array(
72
   protected $configuration = array(
73
      'tables' => array(
73
      'tables' => array(
74
         'users'  => array(
74
         'users'  => array(
75
            'table'     => '_users',   // table name for user records
75
            'table'     => '_users',   // table name for user records
76
            'id'        => '_user_id', // ID column name
76
            'id'        => '_user_id', // ID column name
77
            'display'   => array(      // fields which are displayed to select
77
            'display'   => array(      // fields which are displayed to select
Line 108... Line 108...
108
               )
108
               )
109
            )
109
            )
110
         )
110
         )
111
      );
111
      );
112
      /** @var mysqli $dbConnection Holds the mysqli database connection */
112
      /** @var mysqli $dbConnection Holds the mysqli database connection */
113
      private $dbConnection = false;
113
      protected $dbConnection = false;
114
      
114
      
115
      /**
115
      /**
116
       * constructor for an instance of the class
116
       * constructor for an instance of the class
117
       * 
117
       * 
118
       * If $dbConnection is not null, will be used for database access
118
       * If $dbConnection is not null, will be used for database access
119
       * If $dbLoginInfo is not null, will override $dbConnection, make
119
       * If $dbLoginInfo is not null, will override $dbConnection, make
120
       * a new connection and use that.
120
       * a new connection and use that.
121
       * 
121
       * 
122
       * If $dbDef is set, will be merged with $dbDefinition
122
       * If $dbDef is set, will be merged with $configuration
123
       * 
123
       * 
124
       * @param mysqli $dbConnection Existing mysqli database connection
124
       * @param mysqli $dbConnection Existing mysqli database connection
125
       * @param string[] $dbDef Array to be merged with $dbDefinition
125
       * @param string[] $dbDef Array to be merged with $configuration
126
       * @param string[] $dbLoginInfo Array containing username, hostname, etc.. to make mysqli connection_aborted
126
       * @param string[] $dbLoginInfo Array containing username, hostname, etc.. to make mysqli connection_aborted
127
       * 
127
       * 
128
       * @return null
128
       * @return null
129
       * 
129
       * 
130
       */
130
       */
131
      public function __construct( $dbConnection = null, $dbDef = array(), $dbLoginInfo = array() ) {
131
      public function __construct( $dbConnection = null, $dbDef = array(), $dbLoginInfo = array() ) {
132
         $this->dbConnection = $dbConnection;
132
         $this->dbConnection = $dbConnection;
133
         if ( $dbDef ) {
133
         if ( $dbDef ) {
134
            $this->dbDefinition = array_merge_recursive( $this->dbDefinition, $dbDef );
134
            $this->configuration = array_merge_recursive( $this->configuration, $dbDef );
135
         }
135
         }
136
         if ( $dbLoginInfo ) {
136
         if ( $dbLoginInfo ) {
137
            $this->setDBConnection( $dbLoginInfo );
137
            $this->setDBConnection( $dbLoginInfo );
138
         }
138
         }
139
      }
139
      }
Line 145... Line 145...
145
       * puts single quotes around it
145
       * puts single quotes around it
146
       * 
146
       * 
147
       * @param string $string The string to be fixed
147
       * @param string $string The string to be fixed
148
       * @return string A copy of the string, ready for SQL
148
       * @return string A copy of the string, ready for SQL
149
       */
149
       */
150
      private function escapeString ( $string ) {
150
      protected function escapeString ( $string ) {
151
         $string = $this->dbConnection->real_escape_string( $string );
151
         $string = $this->dbConnection->real_escape_string( $string );
152
         if ( ! is_numeric( $string ) )
152
         if ( ! is_numeric( $string ) )
153
            $string = "'$string'";
153
            $string = "'$string'";
154
         return $string;
154
         return $string;
155
      }
155
      }
Line 161... Line 161...
161
       * parameters set to null, will retrieve all columns and records
161
       * parameters set to null, will retrieve all columns and records
162
       * Setting $field and $toFind create a where clause, and setting
162
       * Setting $field and $toFind create a where clause, and setting
163
       * $fieldList as a has (ie, 'fieldname' => 1) will limit the 
163
       * $fieldList as a has (ie, 'fieldname' => 1) will limit the 
164
       * fields returned
164
       * fields returned
165
       * 
165
       * 
166
       * @param string $field A valid field definition from $dbDefinition
166
       * @param string $field A valid field definition from $configuration
167
       * @param string $toFind The string to find, ie where $field = $username
167
       * @param string $toFind The string to find, ie where $field = $username
168
       * @param string[] $fieldList a hash where the keys make a list of columns to return. If empty, returns all columns
168
       * @param string[] $fieldList a hash where the keys make a list of columns to return. If empty, returns all columns
169
       * 
169
       * 
170
       * @return string A cleaned and formatted SQL Query
170
       * @return string A cleaned and formatted SQL Query
171
       * 
171
       * 
172
      */
172
      */
173
      private function buildQuery( $whereFields, $fieldList = null ) {
173
      protected function buildQuery( $whereFields, $fieldList = null ) {
174
         // always get the ID field
174
         // always get the ID field
175
         $fields = array( $this->dbDefinition['tables']['users']['id'] . ' id');
175
         $fields = array( $this->configuration['tables']['users']['id'] . ' id');
176
         // Get the rest of the available fields
176
         // Get the rest of the available fields
177
         foreach ( $this->dbDefinition['tables']['users']['fields'] as $key => $value ) {
177
         foreach ( $this->configuration['tables']['users']['fields'] as $key => $value ) {
178
            // do not use this one if $fieldList doesn't have it
178
            // do not use this one if $fieldList doesn't have it
179
            if ( ! isset( $fieldList ) || isset( $fieldList[$key] ) )
179
            if ( ! isset( $fieldList ) || isset( $fieldList[$key] ) )
180
               $fields[] = $value['dbColumn'] . ' ' . $key;
180
               $fields[] = $value['dbColumn'] . ' ' . $key;
181
         }
181
         }
182
         // Change it into something SQL can handle
182
         // Change it into something SQL can handle
183
         $query = implode( ',', $fields );
183
         $query = implode( ',', $fields );
184
         // now, build the rest of the query
184
         // now, build the rest of the query
185
         $query = "select $query from " . $this->dbDefinition['tables']['users']['table'];
185
         $query = "select $query from " . $this->configuration['tables']['users']['table'];
186
         if ( isset( $whereFields ) ) {
186
         if ( isset( $whereFields ) ) {
187
            $temp = array();
187
            $temp = array();
188
            foreach ( $whereFields as $key => $value ) {
188
            foreach ( $whereFields as $key => $value ) {
189
               $temp[] = ( 
189
               $temp[] = ( 
190
                  $key == 'id' ? 
190
                  $key == 'id' ? 
191
                  $this->dbDefinition['tables']['users']['id'] : 
191
                  $this->configuration['tables']['users']['id'] : 
192
                  $this->dbDefinition['tables']['users']['fields'][$key]['dbColumn']
192
                  $this->configuration['tables']['users']['fields'][$key]['dbColumn']
193
                  ) . '= ' . $this->escapeString( $value );
193
                  ) . '= ' . $this->escapeString( $value );
194
            }
194
            }
195
            $query .= ' where ' . implode( ' and ', $temp );
195
            $query .= ' where ' . implode( ' and ', $temp );
196
         }
196
         }
197
         //print "<p>$query</p>";
197
         //print "<p>$query</p>";
Line 212... Line 212...
212
       * 
212
       * 
213
      */
213
      */
214
      public function getARecord( $whereFields, $fieldList = null ) {
214
      public function getARecord( $whereFields, $fieldList = null ) {
215
         // run the query, placing value in $result
215
         // run the query, placing value in $result
216
         mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
216
         mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
217
         $result = $this->dbConnection->query( $this->buildQuery( $whereFields, $fieldList ) );
217
         $result = $this->doSQL( $this->buildQuery( $whereFields, $fieldList ) );
218
         if ( $result ) { // got one, so return it
218
         if ( $result ) { // got one, so return it
219
            return $result->fetch_assoc();
219
            return $result->fetch_assoc();
220
         }
220
         }
221
         // WTFO? nothing, so return empty array
221
         // WTFO? nothing, so return empty array
222
         return array();
222
         return array();
Line 236... Line 236...
236
      
236
      
237
      /**
237
      /**
238
       * Gets the entire record for a user
238
       * Gets the entire record for a user
239
       * 
239
       * 
240
       * NOTE: this does not actually get all columns. getARecord only gets
240
       * NOTE: this does not actually get all columns. getARecord only gets
241
       * the columns defined in $dbDefinition
241
       * the columns defined in $configuration
242
       * 
242
       * 
243
       * @param string $username the value of the login field to find
243
       * @param string $username the value of the login field to find
244
       * 
244
       * 
245
       * @return string[] fieldname=>value array of found record
245
       * @return string[] fieldname=>value array of found record
246
       */
246
       */
Line 252... Line 252...
252
       * Make the database connection
252
       * Make the database connection
253
       * 
253
       * 
254
       * @param string[] $parameters Parameters for makeing the connection
254
       * @param string[] $parameters Parameters for makeing the connection
255
       * @return mysqli|false
255
       * @return mysqli|false
256
       */
256
       */
257
      private function setDBConnection ( $parameters ) {
257
      protected function setDBConnection ( $parameters ) {
258
         if ( !isset($parameters['username'], $parameters['password'],$parameters['database']  )) {
258
         if ( !isset($parameters['username'], $parameters['password'],$parameters['database']  )) {
259
            return false;
259
            return false;
260
         }
260
         }
261
         if ( !isset( $parameters['host'] ) ) {
261
         if ( !isset( $parameters['host'] ) ) {
262
            $parameters['host'] = 'localhost';
262
            $parameters['host'] = 'localhost';
Line 264... Line 264...
264
         mysqli_report( MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT );
264
         mysqli_report( MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT );
265
         $this->dbConnection = new mysqli( $parameters['host'], $parameters['username'], $parameters['password'],$parameters['database'] );
265
         $this->dbConnection = new mysqli( $parameters['host'], $parameters['username'], $parameters['password'],$parameters['database'] );
266
      }
266
      }
267
 
267
 
268
      /**
268
      /**
269
       * Convenience function to create the table
269
       * Convenience function to create the tables defined in $configuration
270
       * 
270
       * 
271
       * Using $dbDefinition, build the table (replacing the current one)
271
       * Using $configuration, build the table (replacing the current one)
272
       * then add $username with $password, setting as admin
272
       * then add $username with $password, setting as admin
273
       * 
273
       * 
274
       * @param string $username The username to create
-
 
275
       * @param string $password The password for this record
-
 
276
       * @param bool $admin Whether the user is an admin or not
-
 
277
       * 
-
 
278
       * @return bool true if table was created
-
 
279
       * 
-
 
280
      */
274
      */
281
      public function buildTable( $username, $password, $admin = true ) {
275
      public function buildTable( ) {
282
         if ( $this->dbConnection ) {
276
         if ( $this->dbConnection ) {
-
 
277
            foreach ( $this->configuration['tables'] as $table => $tableRecord ) {
283
            $password = password_hash( $password, PASSWORD_DEFAULT );
278
               //print "<pre>Building " . $table . "\n</pre>";
284
            $fields = array( $this->dbDefinition['tables']['users']['id'] . ' int unsigned not null auto_increment' );
279
               $fields = array( $tableRecord['id'] . ' int unsigned not null auto_increment' );
285
            foreach ( $this->dbDefinition['tables']['users']['fields'] as $key => $record ) {
280
               foreach ( $tableRecord['fields'] as $key => $record ) {
-
 
281
                  //print "<pre>\tColumn " . $key . ' using ' . print_r( $record, true)  . "\n</pre>";
286
               $fieldDef = $record['dbColumn'];
282
                  $fieldDef = $record['dbColumn'];
287
               $fieldDef .= ' ' . $record['type'];
283
                  $fieldDef .= ' ' . $record['type'];
288
               if ( isset( $record['size'] ) ) {
284
                  if ( isset( $record['size'] ) ) {
289
                  $fieldDef .= '(' . $record['size'] . ')';
285
                     $fieldDef .= '(' . $record['size'] . ')';
290
               }
286
                  }
291
               if ( isset( $record['required'] ) ) {
287
                  if ( isset( $record['required'] ) ) {
292
                  $fieldDef .= $record['required'] ? ' not null ' : '';
288
                     $fieldDef .= $record['required'] ? ' not null ' : '';
293
               }
289
                  }
294
               if ( isset( $record['default'] ) ) {
290
                  if ( isset( $record['default'] ) ) {
295
                  $fieldDef .= sprintf( " default '%s'", $record['default'] );
291
                     $fieldDef .= sprintf( " default '%s'", $record['default'] );
-
 
292
                  }
-
 
293
                  if ( isset( $record['comment'] ) ) {
-
 
294
                     $fieldDef .= "comment '" . $record['comment'] . "'";
-
 
295
                  }
-
 
296
                  $fields[] = $fieldDef;
296
               }
297
               }
-
 
298
               $fields[] = 'primary key (' . $tableRecord['id'] . ')';
297
               if ( isset( $record['comment'] ) ) {
299
               $query = implode( ',', $fields );
298
                  $fieldDef .= "comment '" . $record['comment'] . "'";
300
               $query = 'create or replace table ' . $tableRecord['table'] .
299
               }
301
                     "($query)";
-
 
302
               //print '<pre>' . $query . "\n</pre>";
300
               $fields[] = $fieldDef;
303
               $this->doSQL( $query );
301
            }
304
            }
302
            $fields[] = 'primary key (' . $this->dbDefinition['tables']['users']['id'] . ')';
-
 
303
            $query = implode( ',', $fields );
-
 
304
            $query = 'create or replace table ' . $this->dbDefinition['tables']['users']['table'] .
-
 
305
                  "($query)";
-
 
306
            $this->dbConnection->query( $query );
-
 
307
            $query = "insert into _users( login, password, isAdmin ) values ( '$username', '$password', '$admin' )";
-
 
308
            $this->dbConnection->query( $query );
-
 
309
         }
-
 
310
         return false;
305
         } // foreach table
311
      } // buildTable
306
      } // buildTable
-
 
307
 
-
 
308
      /**
-
 
309
       * Convenience function to initialize tables to values
-
 
310
       * 
-
 
311
       * @param string[] $initValues Array of tablenames, column names and values
-
 
312
       * 
-
 
313
      */
-
 
314
      public function initTables ( $initValues ) {
-
 
315
         foreach ( $initValues as $table => $fieldDef ) {
-
 
316
            $columns = array();
-
 
317
            $values = array();
-
 
318
            foreach ( $fieldDef as $columnName => $columnValue ) {
-
 
319
               $columns[] = $this->tableColumnName( $table, $columnName );
-
 
320
               $values[] = $this->escapeString( $columnValue );
-
 
321
            }
-
 
322
            $query = sprintf( "insert into %s (%s) values (%s)", 
-
 
323
                  $this->configuration['tables'][$table]['table'],
-
 
324
                  implode( ",", $columns ), 
-
 
325
                  implode( ',', $values ) 
-
 
326
                  );
-
 
327
            //print '<pre>' . $query . "\n</pre>";
-
 
328
            $this->doSQL( $query );
-
 
329
         }
-
 
330
      }
-
 
331
      
-
 
332
      protected function tableColumnName ( $table, $field ) {
-
 
333
         return $this->configuration['tables'][$table]['fields'][$field]['dbColumn'];
-
 
334
      }
312
      
335
      
313
      /**
336
      /**
314
       * Tests that the database connection works and the table is built
337
       * Tests that the database connection works and the table is built
315
       *
338
       *
316
       * @return boolean True if table exists (does not verify columns)
339
       * @return boolean True if table exists (does not verify columns)
317
       */
340
       */
318
      public function test() {
341
      public function test() {
319
         $result = $this->dbConnection->query( sprintf( "show tables like '%s'", $this->dbDefinition['tables']['users']['table'] ) );
342
         $result = $this->doSQL( sprintf( "show tables like '%s'", $this->configuration['tables']['users']['table'] ) );
320
         return $result !== false && $result->num_rows;
343
         return $result !== false && $result->num_rows;
321
      } // test
344
      } // test
322
      
345
      
323
      /**
346
      /**
324
       * updates row in database with $newData
347
       * updates row in database with $newData
Line 333... Line 356...
333
            $newData[$key] = $this->escapeString( $value );
356
            $newData[$key] = $this->escapeString( $value );
334
         }
357
         }
335
         if ( $newData ) { // make sure they sent us something
358
         if ( $newData ) { // make sure they sent us something
336
            if ( $newData['id'] > 0 ) { // we are doing an update
359
            if ( $newData['id'] > 0 ) { // we are doing an update
337
               $fields = array();
360
               $fields = array();
338
               foreach ( $this->dbDefinition['tables']['users']['fields'] as $key => $record ) {
361
               foreach ( $this->configuration['tables']['users']['fields'] as $key => $record ) {
339
                  if ( isset( $newData[$key] ) ) {
362
                  if ( isset( $newData[$key] ) ) {
340
                     $fields[] = $record['dbColumn'] . " = $newData[$key]";
363
                     $fields[] = $record['dbColumn'] . " = $newData[$key]";
341
                  } // if
364
                  } // if
342
               }
365
               }
343
               $query = 'update ' . $this->dbDefinition['tables']['users']['table'] . ' set ' .
366
               $query = 'update ' . $this->configuration['tables']['users']['table'] . ' set ' .
344
                  implode( ',', $fields ) .
367
                  implode( ',', $fields ) .
345
                  ' where ' . $this->dbDefinition['tables']['users']['id'] . ' = ' . 
368
                  ' where ' . $this->configuration['tables']['users']['id'] . ' = ' . 
346
                  $this->dbConnection->real_escape_string( $newData['id'] );
369
                  $this->dbConnection->real_escape_string( $newData['id'] );
347
            } else { // we are doing an insert
370
            } else { // we are doing an insert
348
               $columns = array();
371
               $columns = array();
349
               $values = array();
372
               $values = array();
350
               foreach ( $this->dbDefinition['tables']['users']['fields'] as $key => $record ) {
373
               foreach ( $this->configuration['tables']['users']['fields'] as $key => $record ) {
351
                  if ( isset( $newData[$key] ) ) {
374
                  if ( isset( $newData[$key] ) ) {
352
                     $columns[] = $record['dbColumn'];
375
                     $columns[] = $record['dbColumn'];
353
                     $values[] = $newData[$key];
376
                     $values[] = $newData[$key];
354
                  } // if
377
                  } // if
355
               }
378
               }
356
               $query = 'insert into ' . $this->dbDefinition['tables']['users']['table'] . 
379
               $query = 'insert into ' . $this->configuration['tables']['users']['table'] . 
357
                  '(' . implode( ',', $columns ) . ') values (' .
380
                  '(' . implode( ',', $columns ) . ') values (' .
358
                  implode( ',', $values ) . ')';
381
                  implode( ',', $values ) . ')';
359
            }
382
            }
360
            //print "<p>$query</p>";
383
            //print "<p>$query</p>";
361
            return $this->dbConnection->query( $query );
384
            return $this->doSQL( $query );
362
         }
385
         }
363
      } // update
386
      } // update
364
      
387
      
365
      /**
388
      /**
366
       * retrieves all users from the database
389
       * retrieves all users from the database
Line 371... Line 394...
371
       */
394
       */
372
      public function getAllUsers() {
395
      public function getAllUsers() {
373
         $query = $this->buildQuery( null, null, array('login' => 1) );
396
         $query = $this->buildQuery( null, null, array('login' => 1) );
374
         //print "<p>$query</p>\n";
397
         //print "<p>$query</p>\n";
375
         mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
398
         mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
376
         $result = $this->dbConnection->query( $query );
399
         $result = $this->doSQL( $query );
377
         if ( $result ) {
400
         if ( $result ) {
378
            return $result->fetch_all(MYSQLI_ASSOC);
401
            return $result->fetch_all(MYSQLI_ASSOC);
379
         }
402
         }
380
         return array();
403
         return array();
381
      }
404
      }
-
 
405
      
-
 
406
      /**
-
 
407
       * Executes an SQL statement, returning the result
-
 
408
       * 
-
 
409
       * This simply runs mysqli::query, and returns the value of that
-
 
410
       * 
-
 
411
       * Created for testing and debugging, if the second parameter is 
-
 
412
       * true, will NOT execute the query, but will instead display the 
-
 
413
       * query passed.
-
 
414
       * 
-
 
415
       * @parameter string $query SQL Query to execute
-
 
416
       * @parameter boolean $testing If set to true, displays query instead of executing it
-
 
417
       * 
-
 
418
       * @returns mysqli_result
-
 
419
       */
-
 
420
      protected function doSQL( $query, $testing = false ) {
-
 
421
         if ( $testing ) {
-
 
422
            print "<pre>$query</pre>"; return;
-
 
423
         } else {
-
 
424
            mysqli_report( MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT );
-
 
425
            $result = $this->dbConnection->query( $query );
-
 
426
            return $result;
-
 
427
         }
-
 
428
      }
-
 
429
      
-
 
430
      /**
-
 
431
       * Gets a single field from a table
-
 
432
       * 
-
 
433
       * Builds a query similar to
-
 
434
       * select $returnColumn from $tableName where $fieldName = $value
-
 
435
       * executes it, and returns the first column of the first
-
 
436
       * row returned, or null if it does not exist.
-
 
437
       * 
-
 
438
       * @parameter string $tableName Name of database table
-
 
439
       * @parameter string $returnColumn Column to return
-
 
440
       * @parameter string $fieldName Name of column to search for value
-
 
441
       * @parameter string $value The value to match
-
 
442
       * 
-
 
443
       * @returns string $returnColumn of first row, or null if none
-
 
444
       */
-
 
445
      protected function getAField( $tableName, $returnColumn, $fieldName, $value ) {
-
 
446
         $value = $this->escapeString( $value );
-
 
447
         $result = $this->doSQL( "select $returnColumn from $tableName where $fieldName = $value" );
-
 
448
         $field = $result->fetch_array(MYSQLI_NUM);
-
 
449
         return $field ? $field[0] : null;
-
 
450
      }
382
   
451
   
383
}
452
}
384
 
453
 
385
?>
454
?>