Subversion Repositories php_users

Rev

Rev 20 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
16 rodolico 1
<?php
2
 
3
/*
4
   Copyright (c) 2021, Daily Data, Inc. Redistribution and use in 
5
   source and binary forms, with or without modification, are permitted
6
   provided that the following conditions are met:
7
 
8
   * Redistributions of source code must retain the above copyright 
9
     notice, this list of conditions and the following disclaimer.
10
   * Redistributions in binary form must reproduce the above copyright 
11
     notice, this list of conditions and the following disclaimer in the 
12
     documentation and/or other materials provided with the distribution.
13
 
14
   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
15
   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16
   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17
   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
18
   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19
   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
20
   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21
   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22
   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23
   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24
   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
 
26
*/
27
 
28
/*
29
 * UsersDataSourceMySQLi.class.php
30
 * 
31
 * Authors: R. W. Rodolico
32
 * 
33
 */
34
 
35
/**
36
 * usersPermissionsDataSource class
37
 * 
38
 * usersPermissionsDataSource provides the data access capabilities for
39
 * the usersPermissions class
40
 * class.
41
 * 
42
 * To build a data access class for UsersPermissions, the following 5
43
 * methods must exist.
44
 * getPassword(username)
45
 * getAllUsers()
46
 * getARecord
47
 * update
48
 * 
49
 * Additionally, where appropriate, the following function is useful
50
 * buildTable()
51
 * 
52
 * This particular instance provides an interface to MySQL using
53
 * the mysqli libraries.
54
 * 
55
 * Create an instance of this, then pass the variable to several Users
56
 * calls.
57
 * 
58
 * @author R. W. Rodolico <rodo@unixservertech.com>
59
 * 
60
 * @version 0.9.0 (beta)
61
 * @copyright 2021 Daily Data, Inc.
62
 * 
63
 */
64
 
21 rodolico 65
require_once( 'UsersDataSourceMySQLi.class.php' );
66
 
67
class usersPermissionsDataSourceMySQLi extends usersDataSourceMySQLi {
16 rodolico 68
 
21 rodolico 69
   /**
70
    * extends usersDataSource
71
    * 
72
    * Adds the new fields needed for permissions. First, creates array
73
    * $permissions, then does a recursive merge into 
74
    * usersDataSource::$configuration. 
75
    * NOTE: we must merge this before we merge in $dbDef so the
76
    * developer can modify permissions also
77
    * 
78
    * @param mysqli $connection Existing mysqli database connection
79
    * @param string[] $customFields Array to be merged with $configuration
80
    * @param string[] $dbLoginInfo Array containing username, hostname, etc.. to make mysqli connection_aborted
81
    * 
82
    * @return null
83
    * 
84
    */
85
   public function __construct( $connection, $customFields = array() ) {
20 rodolico 86
      $permissions = array(
87
         'tables' => array(
88
            'permissions categories' => array(
89
               'table'     => '_permissions_categories',   // table name for user records
90
               'id'        => '_permission_category_id', // ID column name
91
               'display'   => array(      // fields which are displayed to select
92
                  'description'
93
                  ),         
94
               'fields' => array(
95
                  'name'  => array(
96
                        'dbColumn'     => 'name',
97
                        'type'         => 'varchar',
98
                        'size'         => 16,
21 rodolico 99
                        'required'     => true,
100
                        'unique'       => true
20 rodolico 101
                        )
102
                  ),
103
               ), // permissions categories table
104
            'permissions' => array(
105
               'table'     => '_permissions',   // table name for user records
106
               'id'        => '_permission_id', // ID column name
107
               'display'   => array(      // fields which are displayed to select
108
                  'description'
109
                  ),         
110
               'fields' => array(
111
                  'name'  => array(
112
                        'dbColumn'     => 'name',
113
                        'type'         => 'varchar',
114
                        'size'         => 16,
21 rodolico 115
                        'required'     => true,
116
                        'unique'       => true
20 rodolico 117
                        ),
118
                  'description'  => array(
119
                        'dbColumn'     => 'description',
120
                        'type'         => 'varchar',
121
                        'size'         => 64,
122
                        'required'     => true
123
                        ),
124
                  'permission category' => array(
125
                        'dbColumn'     => '_permission_category_id',
126
                        'type'         => 'int unsigned',
127
                        'required'     => true,
128
                        ),
129
                  'default'  => array(
130
                        'dbColumn'     => 'default_value',
131
                        'type'         => 'boolean',
132
                        'required'     => true
133
                        ),
134
               )
135
            ), // permissions table
136
            'users permissions' => array(
137
               'table'     => '_users_permissions',   // table name for user records
138
               'id'        => '_user_permission_id', // ID column name
139
               'fields' => array(
140
                  'user_id'  => array(
141
                        'dbColumn'     => '_user_id',
142
                        'type'         => 'int unsigned',
143
                        'required'     => true,
144
                        'references'   => 'users',
145
                        ),
146
                  'permission_id'  => array(
147
                        'dbColumn'     => '_permission_id',
148
                        'type'         => 'int unsigned',
149
                        'required'     => true,
150
                        'references'   => 'permissions',
151
                        ),
152
                  'value'  => array(
153
                        'dbColumn'     => 'value',
154
                        'type'         => 'boolean',
155
                        'required'     => true,
156
                        ),
157
               )
158
            ) // users permissions table
159
         ),
160
         'views' => array(
161
            'users permissions' => array( 
162
               'name' => '_view_users_permissions' 
163
               )
164
            ) // users permissions view
165
         );
166
         $this->configuration = array_merge_recursive( $this->configuration, $permissions );
16 rodolico 167
 
21 rodolico 168
         parent::__construct( $connection, $customFields );
16 rodolico 169
 
21 rodolico 170
   } // constructor
16 rodolico 171
 
21 rodolico 172
   /**
173
    * Function will build tables when called
174
    * 
175
    * Calls parent::buildTable first, then creates a view. The query
176
    * for the view is created using sprintf so we can allow the developers
177
    * to modify the table names, etc...
178
    * 
179
    */
180
   public function buildTable() {
181
      parent::buildTable();
182
      // add a unique constraint on users permissions for user id and permission id
183
      // we do it this way since there is no way to do it automagically
184
      // without rewriting the $configuration code
185
      $query = sprintf( 'alter table %s add unique key (%s,%s)',
186
         $this->configuration['tables']['users permissions']['table'],
187
         $this->configuration['tables']['users permissions']['fields']['user_id']['dbColumn'],
188
         $this->configuration['tables']['users permissions']['fields']['permission_id']['dbColumn']
189
         );
190
      $this->doSQL( $query );
191
      // create a convenience view
192
      $query = sprintf( "create or replace view %s as 
193
         select 
194
            %s.%s users_id,      /* users id */
195
            %s.%s user,          /* users login */
196
            %s.%s permission_id, /* permissions id */
197
            %s.%s permission,    /* permissions name */
198
            %s.%s description,   /* permissions description */
199
            %s.%s category,      /* permissions_categories name */
200
            ifnull(%s.%s,0)  value /* actual value */
201
         from 
202
            %s /* users */
203
            join %s   /* permissions (permissions_id */
204
            left join %s using (%s,%s)   /* users_permissions (users_id) */
205
            join %s using (%s)   /* permissions_categories( permissions_categories_id) */",
206
         $this->configuration['views']['users permissions']['name'],
207
         $this->configuration['tables']['users']['table'],
208
         $this->configuration['tables']['users']['id'],
209
         $this->configuration['tables']['users']['table'],
210
         $this->configuration['tables']['users']['fields']['login']['dbColumn'],
211
         $this->configuration['tables']['permissions']['table'],
212
         $this->configuration['tables']['permissions']['id'],
213
         $this->configuration['tables']['permissions']['table'],
214
         $this->configuration['tables']['permissions']['fields']['name']['dbColumn'],
215
         $this->configuration['tables']['permissions']['table'],
216
         $this->configuration['tables']['permissions']['fields']['description']['dbColumn'],
217
         $this->configuration['tables']['permissions categories']['table'],
218
         $this->configuration['tables']['permissions categories']['fields']['name']['dbColumn'],
219
         $this->configuration['tables']['users permissions']['table'],
220
         $this->configuration['tables']['users permissions']['fields']['value']['dbColumn'],
221
         $this->configuration['tables']['users']['table'],
222
         $this->configuration['tables']['permissions']['table'],
223
         $this->configuration['tables']['users permissions']['table'],
224
         $this->configuration['tables']['users']['id'],
225
         $this->configuration['tables']['permissions']['id'],
226
         $this->configuration['tables']['permissions categories']['table'],
227
         $this->configuration['tables']['permissions categories']['id']
228
       );
229
      $this->doSQL( $query );
230
   }
231
 
232
   /**
233
    * Adds a permission to the permissions table
234
    * 
235
    * This simply adds a permission to the permissions table, adding the 
236
    * category if it doesn't exist already.
237
    * 
238
    * @parameter string $category Category to place the permission into
239
    * @parameter string $name The short name of the permission
240
    * @parameter string $description The long (display) name for the permission
241
    * @parameter boolean $defaultValue The default value for the permission
242
    */
243
   public function addPermission ( $category, $name, $description, $defaultValue = 0 ) {
244
      $categoryID = $this->getAField( 
245
            $this->tableColumnName ( 'permissions categories' ),
246
            $this->tableColumnName ( 'permissions categories', 'id' ),
247
            $this->tableColumnName ( 'permissions categories', 'name' ),
248
            $category
249
         );
250
      if ( ! $categoryID ) { // we did not find the category, so add it
251
         $this->doSQL( sprintf( "insert into %s ( %s ) values ( %s )",
252
            $this->tableColumnName ( 'permissions categories' ),
253
            $this->tableColumnName ( 'permissions categories', 'name' ),
254
            $this->escapeString($category)
255
            )
256
         );
257
         $categoryID = $this->getAField( 
258
            $this->tableColumnName ( 'permissions categories' ),
259
            $this->tableColumnName ( 'permissions categories', 'id' ),
260
            $this->tableColumnName ( 'permissions categories', 'name' ),
261
            $category
262
         );
263
      } // if category not found
264
      $query = sprintf( "insert into %s ( %s,%s,%s,%s ) values ( %s,%s,%s,%s )",
265
            $this->tableColumnName ( 'permissions' ),
266
            $this->tableColumnName ( 'permissions', 'name' ),
267
            $this->tableColumnName ( 'permissions', 'description' ),
268
            $this->tableColumnName ( 'permissions', 'permission category' ),
269
            $this->tableColumnName ( 'permissions', 'default' ),
270
            $this->escapeString($name),
271
            $this->escapeString($description),
272
            $this->escapeString($categoryID),
273
            $defaultValue
274
      );
275
      $this->doSQL( $query );
276
      $permissionsID = $this->getAField( 
16 rodolico 277
            $this->configuration['tables']['permissions']['table'],
278
            $this->configuration['tables']['permissions']['id'],
279
            $this->configuration['tables']['permissions']['fields']['name']['dbColumn'],
21 rodolico 280
            $this->escapeString($name)
16 rodolico 281
         );
21 rodolico 282
   } // addPermission
283
 
284
   /**
285
    * Sets any unset user permissions
286
    * 
287
    * This will set any missing permissions which have a true value in the
288
    * users permissions join table. This will NOT modify any existing records
289
    * but will add new records if they do not exist in the table.
290
    * 
291
    * @parameters string $user_id If set, will limit to only one user (not implemented)
292
    */
293
   public function setUsersPermissions ( $user_id = null ) {
294
      $query = sprintf(
295
         "insert into %s (%s,%s,%s)
296
         select
297
            %s.%s,
298
            %s.%s,
299
            %s.%s
300
         from
301
            %s
302
            join %s
303
         where
304
            %s.%s
305
            and not exists
306
               (
307
                  select 1
308
                  from %s
309
                  where
310
                     %s.%s = %s.%s
311
                     and %s.%s = %s.%s
312
               )",
313
         $this->configuration['tables']['users permissions']['table'],
314
         $this->configuration['tables']['users permissions']['fields']['user_id']['dbColumn'],
315
         $this->configuration['tables']['users permissions']['fields']['permission_id']['dbColumn'],
316
         $this->configuration['tables']['users permissions']['fields']['value']['dbColumn'],
317
         $this->configuration['tables']['users']['table'],
318
         $this->configuration['tables']['users']['id'],
319
         $this->configuration['tables']['permissions']['table'],
320
         $this->configuration['tables']['permissions']['id'],
321
         $this->configuration['tables']['permissions']['table'],
322
         $this->configuration['tables']['permissions']['fields']['default']['dbColumn'],
323
         $this->configuration['tables']['users']['table'],
324
         $this->configuration['tables']['permissions']['table'],
325
         $this->configuration['tables']['permissions']['table'],
326
         $this->configuration['tables']['permissions']['fields']['default']['dbColumn'],
327
         $this->configuration['tables']['users permissions']['table'],
328
         $this->configuration['tables']['users permissions']['table'],
329
         $this->configuration['tables']['users permissions']['fields']['user_id']['dbColumn'],
330
         $this->configuration['tables']['users']['table'],
331
         $this->configuration['tables']['users']['id'],
332
         $this->configuration['tables']['users permissions']['table'],
333
         $this->configuration['tables']['users permissions']['fields']['permission_id']['dbColumn'],
334
         $this->configuration['tables']['permissions']['table'],
335
         $this->configuration['tables']['permissions']['id']
336
         );
337
         $this->doSQL($query, true );
338
   } // setUsersPermissions
339
 
340
   public function getARecord( $whereFields, $fieldList = null ) {
341
      $id = isset( $whereFields['id'] ) ? $whereFields['id'] : null;
342
      $result = parent::getARecord( $whereFields, $fieldList );
343
      if ( $result && isset( $id ) ) {
344
         $result['permissions'] = $this->getPermissions( $id );
17 rodolico 345
      }
21 rodolico 346
      return $result;
347
   }
348
 
349
 
350
   /**
351
    * Gets permissions for one user
352
    * 
353
    * NOTE: if $id is -1, indicating a new user, simply retrieves all
354
    * permissions from the permissions table with the default value
355
    * 
356
    * WARNING: this uses the view, which is not as flexible as the
357
    * tables as far as modifying programmatically
358
    * 
359
    * The return value is an associative array, where the key is
360
    * the permission (short) name and the value is 0 or 1 (boolean
361
    * true/false)
362
    * 
363
    * @param integer $id the user id of the record we want.
364
    * 
365
    * @returns string[] Array of associative arrays with all data
366
    */
367
   public function getPermissions ( $id ) {
368
      $query = '';
369
      if ( $id == -1 ) {
370
         $query = "select name permission,default_value value from _permissions";
371
      } else {
372
         $query = "select permission,value from _view_users_permissions where users_id = $id";
17 rodolico 373
      }
21 rodolico 374
      $results = $this->doSQL( $query );
375
      $values = $results->fetch_all(MYSQLI_ASSOC);
376
      return array_column( $values, 'value', 'permission' );
377
   }
378
 
379
   /**
380
    * Gets all permissions with names, group names, etc... from database
381
    * 
382
    * NOTE: if $id is -1, indicating a new user, simply retrieves all
383
    * permissions from the permissions table with the default value
384
    * 
385
    * WARNING: this uses the view, which is not as flexible as the
386
    * tables as far as modifying programmatically
387
    * 
388
    * @param integer $id the user id of the record we want.
389
    * @returns string[] Array of associative arrays with all data
390
    */
391
   public function getFullPermissions( $id ) {
392
      $query = '';
393
      if ( $id == -1 ) {
394
         $query = "select _permission_id permission_id, _permissions.name permission, description, _permissions_categories.name category, default_value value from _permissions join _permissions_categories using (_permission_category_id)";
395
      } else {
396
         $query = "select permission_id,permission,description,category,value from _view_users_permissions where users_id = $id order by category,description";
17 rodolico 397
      }
21 rodolico 398
      $results = $this->doSQL( $query );
399
      return $results->fetch_all(MYSQLI_ASSOC);
400
   }
16 rodolico 401
 
21 rodolico 402
   /**
403
    * Adds/Updates a group of permissions for a user
404
    * 
405
    * @param integer $userID The user ID to update
406
    * @param string[] $newData An array where the key is the field name and the value is the new value to use
407
    */
408
   public function updatePermissions ( $userID, $newData ) {
409
      $query = '';
410
      foreach ( $newData as $key => $value ) {
411
         $query = sprintf(
412
               "insert into %s 
413
                  ( %s,%s,%s ) 
414
                  select %s, %s, %s 
415
                  from %s
416
                  where %s = %s 
417
               on duplicate key update %s = %s",
418
            $this->tableColumnName ( 'users permissions' ),
419
            $this->tableColumnName ( 'users permissions', 'user_id' ),
420
            $this->tableColumnName ( 'users permissions', 'permission_id' ),
421
            $this->tableColumnName ( 'users permissions', 'value' ),
422
            $userID,
423
            $this->tableColumnName ( 'permissions', 'id', true ),
424
            $value,
425
            $this->tableColumnName ( 'permissions' ),
426
            $this->tableColumnName ( 'permissions', 'name' ),
427
            $this->escapeString($key),
428
            $this->tableColumnName ( 'users permissions', 'value' ),
429
            $value
430
         );
431
         $this->doSQL( $query );
432
      }
433
   } // update
434
 
16 rodolico 435
}
436
 
437
?>