1: | <?php |
2: | declare(strict_types=1); |
3: | |
4: | |
5: | |
6: | |
7: | |
8: | |
9: | |
10: | |
11: | |
12: | |
13: | |
14: | |
15: | use Module\Support\Sql; |
16: | |
17: | |
18: | |
19: | |
20: | |
21: | |
22: | |
23: | |
24: | class Sql_Module extends Sql |
25: | { |
26: | use NamespaceUtilitiesTrait; |
27: | const MYSQL_USER_FIELD_SIZE = 16; |
28: | |
29: | |
30: | const PG_TEMP_PASSWORD = '23f!eoj3'; |
31: | const MYSQL_DATADIR = '/var/lib/mysql'; |
32: | const PGSQL_DATADIR = '/var/lib/pgsql'; |
33: | const MIN_PASSWORD_LENGTH = 3; |
34: | |
35: | |
36: | |
37: | const PER_DATABASE_CONNECTION_LIMIT = 20; |
38: | |
39: | |
40: | |
41: | const MIN_PREFIX_LENGTH = 3; |
42: | |
43: | const MASTER_USER = 'root'; |
44: | |
45: | |
46: | |
47: | |
48: | const DB_BIN2TXT_MULT = 1.5; |
49: | protected const PGSQL_PERMITTED_EXTENSIONS = ['pg_trgm', 'hstore']; |
50: | protected $exportedFunctions = [ |
51: | '*' => PRIVILEGE_SITE, |
52: | 'get_prefix' => PRIVILEGE_SITE | PRIVILEGE_USER, |
53: | 'pgsql_version' => PRIVILEGE_ALL, |
54: | 'mysql_version' => PRIVILEGE_ALL, |
55: | 'version' => PRIVILEGE_ALL, |
56: | 'get_mysql_uptime' => PRIVILEGE_ALL, |
57: | 'assert_mysql_permissions' => PRIVILEGE_SITE | PRIVILEGE_SERVER_EXEC, |
58: | |
59: | 'get_pgsql_uptime' => PRIVILEGE_ALL, |
60: | 'set_mysql_option' => PRIVILEGE_ALL, |
61: | 'get_mysql_option' => PRIVILEGE_ALL, |
62: | 'get_pgsql_username' => PRIVILEGE_ALL, |
63: | 'get_pgsql_password' => PRIVILEGE_ALL, |
64: | 'set_pgsql_password' => PRIVILEGE_ALL, |
65: | 'export_mysql_pipe_real' => PRIVILEGE_SITE | PRIVILEGE_SERVER_EXEC, |
66: | 'export_pgsql_pipe_real' => PRIVILEGE_SITE | PRIVILEGE_SERVER_EXEC, |
67: | 'enabled' => PRIVILEGE_SITE | PRIVILEGE_USER, |
68: | 'repair_mysql_database' => PRIVILEGE_SITE | PRIVILEGE_ADMIN, |
69: | |
70: | |
71: | 'get_database_size' => PRIVILEGE_SITE | PRIVILEGE_ADMIN, |
72: | 'mysql_database_exists' => PRIVILEGE_SITE | PRIVILEGE_ADMIN, |
73: | 'pgsql_database_exists' => PRIVILEGE_SITE | PRIVILEGE_ADMIN, |
74: | '_export_mysql_old' => PRIVILEGE_SITE | PRIVILEGE_SERVER_EXEC, |
75: | ]; |
76: | |
77: | |
78: | |
79: | |
80: | |
81: | |
82: | public function __construct() |
83: | { |
84: | parent::__construct(); |
85: | if (!AUTH_ALLOW_DATABASE_CHANGE) { |
86: | $this->exportedFunctions['change_prefix'] = PRIVILEGE_NONE; |
87: | } |
88: | } |
89: | |
90: | public function mysql_user_exists($user, $host = 'localhost') |
91: | { |
92: | return parent::__call('mysql_user_exists', [$user, $host]); |
93: | } |
94: | |
95: | |
96: | |
97: | |
98: | |
99: | |
100: | |
101: | |
102: | |
103: | public function delete_mysql_user($user, $host, $cascade = true) |
104: | { |
105: | return $this->mysql_delete_user($user, $host, $cascade); |
106: | } |
107: | |
108: | public function pgsql_user_exists($user) |
109: | { |
110: | |
111: | return parent::__call('pgsql_user_exists', [$user]); |
112: | } |
113: | |
114: | |
115: | |
116: | |
117: | |
118: | |
119: | |
120: | |
121: | |
122: | public function delete_pgsql_user($user, $cascade = false) |
123: | { |
124: | return $this->pgsql_delete_user($user, $cascade); |
125: | |
126: | } |
127: | |
128: | |
129: | |
130: | |
131: | |
132: | |
133: | |
134: | |
135: | |
136: | |
137: | public function store_sql_password($sqlpasswd, $type) |
138: | { |
139: | if ($type != 'mysql' && $type != 'postgresql' && $type != 'pgsql') { |
140: | return error($type . ': unrecognized type'); |
141: | } |
142: | if ($type === 'postgresql') { |
143: | $type = 'pgsql'; |
144: | } |
145: | $fn = "{$type}_store_password"; |
146: | |
147: | return $this->$fn($sqlpasswd); |
148: | } |
149: | |
150: | |
151: | |
152: | |
153: | |
154: | |
155: | |
156: | |
157: | |
158: | |
159: | |
160: | |
161: | public function set_mysql_option($option, $value = null, $group = 'client') |
162: | { |
163: | return $this->mysql_set_option($option, $value, $group); |
164: | |
165: | } |
166: | |
167: | public function set_pgsql_password($password) |
168: | { |
169: | return $this->pgsql_set_password($password); |
170: | |
171: | } |
172: | |
173: | public function set_pgsql_username($user) |
174: | { |
175: | return $this->pgsql_set_username($user); |
176: | |
177: | } |
178: | |
179: | public function get_pgsql_password($user = null) |
180: | { |
181: | return $this->pgsql_get_password($user); |
182: | } |
183: | |
184: | |
185: | |
186: | |
187: | |
188: | |
189: | |
190: | |
191: | public function get_mysql_option($option, $group = 'client') |
192: | { |
193: | return $this->mysql_get_option($option, $group); |
194: | } |
195: | |
196: | public function get_elevated_password_backend() |
197: | { |
198: | return Opcenter\Database\MySQL::rootPassword(); |
199: | } |
200: | |
201: | |
202: | |
203: | |
204: | public function import_mysql($db, $file) |
205: | { |
206: | return $this->mysql_import($db, $file); |
207: | } |
208: | |
209: | |
210: | |
211: | |
212: | |
213: | |
214: | |
215: | public function list_mysql_databases() |
216: | { |
217: | return $this->mysql_list_databases(); |
218: | } |
219: | |
220: | |
221: | |
222: | |
223: | |
224: | |
225: | |
226: | |
227: | |
228: | public function change_prefix($prefix) |
229: | { |
230: | if (!IS_CLI) { |
231: | return $this->query('sql_change_prefix', $prefix); |
232: | } |
233: | if ($this->auth_is_demo()) { |
234: | return error('cannot change prefix in demo mode'); |
235: | } |
236: | $prefix = strtolower(rtrim($prefix, '_')); |
237: | $normalizedPrefix = $prefix . '_'; |
238: | if (strlen($prefix) < static::MIN_PREFIX_LENGTH) { |
239: | return error("minimum acceptable db prefix length is `%d'", static::MIN_PREFIX_LENGTH); |
240: | } else if (!preg_match(Regex::compile(Regex::SQL_PREFIX, ['max' => 14]), $normalizedPrefix)) { |
241: | return error("invalid db prefix `%s'", $prefix); |
242: | } |
243: | $editor = new \Util_Account_Editor($this->getAuthContext()->getAccount(), $this->getAuthContext()); |
244: | $editor->setConfig('mysql', 'dbaseprefix', $normalizedPrefix); |
245: | if ($this->pgsql_enabled()) { |
246: | $editor->setConfig('pgsql', 'dbaseprefix', $normalizedPrefix); |
247: | } |
248: | $status = $editor->edit(); |
249: | if (!$status) { |
250: | return error('failed to change database prefix'); |
251: | } |
252: | |
253: | return $status; |
254: | } |
255: | |
256: | public function get_sql_prefix() |
257: | { |
258: | deprecated('use sql_get_prefix'); |
259: | |
260: | return $this->get_prefix(); |
261: | } |
262: | |
263: | public function get_prefix() |
264: | { |
265: | return $this->getServiceValue('mysql','enabled') ? |
266: | $this->getServiceValue('mysql', 'dbaseprefix') : $this->getServiceValue('pgsql', 'dbaseprefix'); |
267: | } |
268: | |
269: | |
270: | |
271: | |
272: | |
273: | public function list_mysql_users() |
274: | { |
275: | return $this->mysql_list_users(); |
276: | } |
277: | |
278: | |
279: | |
280: | |
281: | public function add_mysql_user( |
282: | $user, |
283: | $host, |
284: | $password, |
285: | $maxconn = 5, |
286: | $maxupdates = 0, |
287: | $maxquery = 0, |
288: | $ssl = '', |
289: | $cipher = '', |
290: | $issuer = '', |
291: | $subject = '' |
292: | ) { |
293: | return $this->mysql_add_user($user, $host, $password, |
294: | $maxconn, $maxupdates, $maxquery, $ssl, $cipher, $issuer, $subject); |
295: | } |
296: | |
297: | public function get_mysql_database_charset($db) |
298: | { |
299: | return $this->mysql_get_database_charset($db); |
300: | } |
301: | |
302: | |
303: | |
304: | |
305: | |
306: | |
307: | |
308: | |
309: | |
310: | |
311: | public function create_mysql_database($db, $charset = 'latin1', $collation = 'latin1_general_ci') |
312: | { |
313: | return $this->mysql_create_database($db); |
314: | } |
315: | |
316: | public function mysql_charset_valid($charset) |
317: | { |
318: | return parent::__call('mysql_charset_valid', [$charset]); |
319: | } |
320: | |
321: | public function get_supported_mysql_charsets() |
322: | { |
323: | return $this->mysql_get_supported_charsets(); |
324: | } |
325: | |
326: | |
327: | |
328: | |
329: | |
330: | |
331: | |
332: | public function mysql_collation_valid($collation) |
333: | { |
334: | return parent::__call('mysql_collation_valid', [$collation]); |
335: | } |
336: | |
337: | public function get_supported_mysql_collations() |
338: | { |
339: | return $this->mysql_get_supported_collations(); |
340: | } |
341: | |
342: | |
343: | |
344: | |
345: | |
346: | |
347: | |
348: | |
349: | |
350: | public function mysql_collation_compatible($collation, $charset) |
351: | { |
352: | return parent::__call('mysql_collation_compatible', [$collation, $charset]); |
353: | } |
354: | |
355: | |
356: | |
357: | |
358: | |
359: | |
360: | |
361: | public function mysql_database_exists($db) |
362: | { |
363: | return parent::__call('mysql_database_exists', [$db]); |
364: | } |
365: | |
366: | |
367: | |
368: | |
369: | |
370: | |
371: | |
372: | |
373: | |
374: | |
375: | |
376: | |
377: | |
378: | public function add_mysql_user_permissions($user, $host, $db, array $opts) |
379: | { |
380: | deprecated_func('use set_mysql_privileges()'); |
381: | |
382: | return $this->set_mysql_privileges($user, $host, $db, $opts); |
383: | } |
384: | |
385: | |
386: | |
387: | |
388: | |
389: | |
390: | |
391: | |
392: | |
393: | |
394: | public function set_mysql_privileges($user, $host, $db, array $privileges) |
395: | { |
396: | return $this->mysql_set_privileges($user, $host, $db, $privileges); |
397: | } |
398: | |
399: | |
400: | |
401: | |
402: | |
403: | |
404: | public function delete_mysql_user_permissions($user, $host, $db) |
405: | { |
406: | deprecated_func('use revoke_from_mysql_db()'); |
407: | |
408: | return $this->revoke_from_mysql_db($user, $host, $db); |
409: | } |
410: | |
411: | |
412: | |
413: | |
414: | |
415: | |
416: | |
417: | |
418: | |
419: | public function revoke_from_mysql_db($user, $host, $db) |
420: | { |
421: | return $this->mysql_revoke_privileges($user, $host, $db); |
422: | } |
423: | |
424: | |
425: | |
426: | public function get_mysql_user_permissions($user, $host, $db) |
427: | { |
428: | deprecated_func('use get_mysql_privileges()'); |
429: | |
430: | return $this->get_mysql_privileges($user, $host, $db); |
431: | } |
432: | |
433: | |
434: | |
435: | |
436: | |
437: | |
438: | |
439: | |
440: | |
441: | |
442: | |
443: | public function get_mysql_privileges($user, $host, $db) |
444: | { |
445: | return $this->mysql_get_privileges($user, $host, $db); |
446: | } |
447: | |
448: | |
449: | |
450: | |
451: | |
452: | |
453: | |
454: | |
455: | |
456: | |
457: | |
458: | |
459: | public function mysql_version($pretty = false) |
460: | { |
461: | return parent::__call('mysql_version', [$pretty]); |
462: | |
463: | } |
464: | |
465: | |
466: | |
467: | |
468: | |
469: | |
470: | |
471: | public function delete_mysql_database($db) |
472: | { |
473: | return $this->mysql_delete_database($db); |
474: | } |
475: | |
476: | |
477: | |
478: | |
479: | |
480: | |
481: | |
482: | public function delete_mysql_backup($db) |
483: | { |
484: | return $this->mysql_delete_backup($db); |
485: | } |
486: | |
487: | |
488: | |
489: | |
490: | public function assert_mysql_permissions() |
491: | { |
492: | return $this->mysql_assert_permissions(); |
493: | } |
494: | |
495: | |
496: | |
497: | |
498: | |
499: | |
500: | |
501: | |
502: | |
503: | |
504: | |
505: | |
506: | |
507: | |
508: | |
509: | |
510: | |
511: | |
512: | |
513: | |
514: | |
515: | public function edit_mysql_user($user, $host, $opts) |
516: | { |
517: | return $this->mysql_edit_user($user, $host, $opts); |
518: | } |
519: | |
520: | |
521: | |
522: | |
523: | |
524: | |
525: | |
526: | |
527: | |
528: | |
529: | public function service_enabled($service) |
530: | { |
531: | deprecated('use enabled()'); |
532: | |
533: | return $this->enabled($service); |
534: | } |
535: | |
536: | |
537: | |
538: | |
539: | |
540: | |
541: | |
542: | |
543: | |
544: | public function enabled($svc_name) |
545: | { |
546: | if ($svc_name != 'mysql' && $svc_name != 'postgresql' && $svc_name != 'pgsql') { |
547: | return error('Invalid service'); |
548: | } |
549: | |
550: | if ($svc_name == 'postgresql') { |
551: | $svc_name = 'pgsql'; |
552: | } |
553: | $fn = "{$svc_name}_enabled"; |
554: | |
555: | return $this->$fn(); |
556: | } |
557: | |
558: | |
559: | |
560: | |
561: | public function add_pgsql_user($user, $password, $maxconn = 5) |
562: | { |
563: | return $this->pgsql_add_user($user, $password, $maxconn); |
564: | } |
565: | |
566: | |
567: | |
568: | |
569: | |
570: | |
571: | |
572: | public function create_pgsql_database($db) |
573: | { |
574: | return $this->pgsql_create_database($db); |
575: | } |
576: | |
577: | |
578: | |
579: | |
580: | |
581: | |
582: | |
583: | public function pgsql_database_exists($db) |
584: | { |
585: | return parent::__call('pgsql_database_exists', [$db]); |
586: | } |
587: | |
588: | |
589: | |
590: | |
591: | |
592: | |
593: | |
594: | public function prep_tablespace() |
595: | { |
596: | return $this->pgsql_prep_tablespace(); |
597: | } |
598: | |
599: | public function add_pgsql_extension($db, $extension) |
600: | { |
601: | return $this->pgsql_add_extension($db, $extension); |
602: | } |
603: | |
604: | |
605: | |
606: | |
607: | |
608: | |
609: | |
610: | public function list_pgsql_databases() |
611: | { |
612: | return $this->pgsql_list_databases(); |
613: | } |
614: | |
615: | |
616: | |
617: | |
618: | |
619: | |
620: | |
621: | |
622: | |
623: | |
624: | public function add_pgsql_user_permissions($user, $db, array $opts) |
625: | { |
626: | return error('Function not implemented in PostgreSQL'); |
627: | } |
628: | |
629: | public function delete_pgsql_user_permissions($user, $db) |
630: | { |
631: | return error('Function not implemented in PostgreSQL'); |
632: | } |
633: | |
634: | |
635: | |
636: | |
637: | |
638: | |
639: | |
640: | public function get_pgsql_user_permissions($user, $db) |
641: | { |
642: | return error('Function not implemented in PostgreSQL'); |
643: | } |
644: | |
645: | |
646: | |
647: | |
648: | |
649: | |
650: | |
651: | |
652: | public function delete_pgsql_database($db) |
653: | { |
654: | return $this->pgsql_delete_database($db); |
655: | } |
656: | |
657: | |
658: | |
659: | |
660: | |
661: | |
662: | |
663: | public function delete_pgsql_backup($db) |
664: | { |
665: | return $this->pgsql_delete_backup($db); |
666: | } |
667: | |
668: | |
669: | |
670: | |
671: | |
672: | |
673: | |
674: | |
675: | |
676: | |
677: | |
678: | |
679: | |
680: | |
681: | |
682: | public function edit_pgsql_user($user, $password, $maxconn = null) |
683: | { |
684: | return $this->pgsql_edit_user($user, $password, $maxconn); |
685: | } |
686: | |
687: | public function get_pgsql_username() |
688: | { |
689: | return $this->pgsql_get_username(); |
690: | } |
691: | |
692: | |
693: | |
694: | |
695: | |
696: | |
697: | |
698: | public function list_pgsql_users() |
699: | { |
700: | return $this->pgsql_list_users(); |
701: | } |
702: | |
703: | |
704: | |
705: | |
706: | |
707: | |
708: | |
709: | public function pg_vacuum_db($db) |
710: | { |
711: | return $this->pgsql_vacuum($db); |
712: | } |
713: | |
714: | public function truncate_pgsql_database($db) |
715: | { |
716: | return $this->pgsql_truncate_database($db); |
717: | } |
718: | |
719: | public function pgsql_version($pretty = false) |
720: | { |
721: | return parent::__call('pgsql_version', [$pretty]); |
722: | } |
723: | |
724: | public function empty_pgsql_database($db) |
725: | { |
726: | return $this->pgsql_empty_database($db); |
727: | } |
728: | |
729: | |
730: | |
731: | |
732: | public function import_pgsql($db, $file) |
733: | { |
734: | return $this->pgsql_import($db, $file); |
735: | } |
736: | |
737: | public function truncate_mysql_database($db) |
738: | { |
739: | return $this->mysql_truncate_database($db); |
740: | } |
741: | |
742: | public function empty_mysql_database($db) |
743: | { |
744: | return $this->mysql_empty_database($db); |
745: | } |
746: | |
747: | |
748: | |
749: | |
750: | |
751: | |
752: | |
753: | |
754: | public function export_mysql($db, $file = null) |
755: | { |
756: | return $this->mysql_export($db, $file); |
757: | } |
758: | |
759: | |
760: | |
761: | |
762: | |
763: | |
764: | |
765: | |
766: | |
767: | |
768: | public function get_database_size($type, $db) |
769: | { |
770: | $type = strtolower($type); |
771: | if ($type != 'mysql' && $type != 'postgresql' && $type != 'pgsql') { |
772: | return error($type . ': invalid database type'); |
773: | } |
774: | if ($type === 'postgresql') { |
775: | $type = 'pgsql'; |
776: | } |
777: | $fn = "{$type}_get_database_size"; |
778: | |
779: | return $this->$fn($db); |
780: | } |
781: | |
782: | |
783: | |
784: | |
785: | |
786: | |
787: | |
788: | |
789: | |
790: | |
791: | public function export_mysql_pipe($db) |
792: | { |
793: | return $this->mysql_export_pipe($db); |
794: | } |
795: | |
796: | |
797: | |
798: | |
799: | |
800: | |
801: | |
802: | |
803: | |
804: | |
805: | |
806: | |
807: | |
808: | |
809: | |
810: | public function export_mysql_pipe_real($db, $user) |
811: | { |
812: | return $this->mysql_export_pipe_real($db, $user); |
813: | } |
814: | |
815: | |
816: | |
817: | public function export_pgsql($db, $file = null) |
818: | { |
819: | return $this->pgsql_export($db, $file); |
820: | } |
821: | |
822: | |
823: | |
824: | |
825: | |
826: | |
827: | |
828: | public function export_pgsql_pipe($db) |
829: | { |
830: | return $this->pgsql_export_pipe($db); |
831: | } |
832: | |
833: | |
834: | |
835: | |
836: | |
837: | |
838: | public function get_pgsql_uptime() |
839: | { |
840: | return $this->pgsql_get_uptime(); |
841: | } |
842: | |
843: | |
844: | |
845: | |
846: | |
847: | |
848: | public function get_mysql_uptime() |
849: | { |
850: | return $this->mysql_get_uptime(); |
851: | |
852: | } |
853: | |
854: | |
855: | |
856: | public function add_mysql_backup($db, $extension = 'zip', $span = 5, $preserve = '0', $email = '') |
857: | { |
858: | return $this->mysql_add_backup($db, $extension, $span, $preserve, $email); |
859: | |
860: | } |
861: | |
862: | public function add_pgsql_backup($db, $extension = 'zip', $span = 5, $preserve = '0', $email = '') |
863: | { |
864: | return $this->pgsql_add_backup($db, $extension, $span, $preserve, $email); |
865: | } |
866: | |
867: | public function edit_mysql_backup($db, $extension, $span = '0', $preserve = '0', $email = '') |
868: | { |
869: | return $this->mysql_edit_backup($db, $extension, $span, $preserve, $email); |
870: | } |
871: | |
872: | public function edit_pgsql_backup($db, $extension, $span = '0', $preserve = '0', $email = '') |
873: | { |
874: | return $this->pgsql_edit_backup($db, $extension, $span, $preserve, $email); |
875: | } |
876: | |
877: | public function list_mysql_backups() |
878: | { |
879: | return $this->mysql_list_backups(); |
880: | } |
881: | |
882: | public function list_pgsql_backups() |
883: | { |
884: | return $this->pgsql_list_backups(); |
885: | } |
886: | |
887: | |
888: | |
889: | |
890: | |
891: | |
892: | |
893: | |
894: | |
895: | |
896: | |
897: | |
898: | |
899: | public function get_mysql_backup_config($db) |
900: | { |
901: | return $this->mysql_get_backup_config($db); |
902: | } |
903: | |
904: | |
905: | |
906: | |
907: | |
908: | |
909: | |
910: | |
911: | |
912: | public function get_pgsql_backup_config($db) |
913: | { |
914: | return $this->pgsql_get_backup_config($db); |
915: | } |
916: | |
917: | public function repair_mysql_database($db) |
918: | { |
919: | return $this->mysql_repair_database($db); |
920: | } |
921: | |
922: | |
923: | |
924: | |
925: | |
926: | |
927: | |
928: | |
929: | public function mysql_kill($id) |
930: | { |
931: | return parent::__call('mysql_kill', [$id]); |
932: | } |
933: | |
934: | |
935: | |
936: | |
937: | |
938: | |
939: | |
940: | |
941: | |
942: | |
943: | |
944: | |
945: | |
946: | |
947: | |
948: | |
949: | |
950: | |
951: | |
952: | |
953: | public function mysql_processlist() |
954: | { |
955: | return parent::__call('mysql_processlist'); |
956: | } |
957: | |
958: | |
959: | |
960: | |
961: | |
962: | |
963: | |
964: | public function mysql_schema_column_maxlen($field) |
965: | { |
966: | return parent::__call('mysql_schema_column_maxlen', [$field]); |
967: | } |
968: | |
969: | public function _edit() |
970: | { |
971: | return true; |
972: | } |
973: | |
974: | public function _delete() |
975: | { |
976: | return true; |
977: | } |
978: | |
979: | |
980: | } |
981: | |