@@ -88,7 +88,19 @@ class MysqliDb
88
88
* @var array
89
89
*/
90
90
protected $ _groupBy = array ();
91
-
91
+
92
+ /**
93
+ * Dynamic type list for tempromary locking tables.
94
+ * @var array
95
+ */
96
+ protected $ _tableLocks = array ();
97
+
98
+ /**
99
+ * Variable which holds the current table lock method.
100
+ * @var string
101
+ */
102
+ protected $ _tableLockMethod = "READ " ;
103
+
92
104
/**
93
105
* Dynamic array that holds a combination of where condition/table data value types and parameter references
94
106
* @var array
@@ -381,6 +393,28 @@ public function setPrefix($prefix = '')
381
393
return $ this ;
382
394
}
383
395
396
+ /**
397
+ * Pushes a unprepared statement to the mysqli stack.
398
+ * WARNING: Use with caution.
399
+ * This method does not escape strings by default so make sure you'll never use it in production.
400
+ *
401
+ * @author Jonas Barascu
402
+ * @param [[Type]] $query [[Description]]
403
+ */
404
+ private function queryUnprepared ($ query )
405
+ {
406
+ // Execute query
407
+ $ stmt = $ this ->mysqli ()->query ($ query );
408
+
409
+ // Failed?
410
+ if (!$ stmt ){
411
+ throw new Exception ("Unprepared Query Failed, ERRNO: " .$ this ->mysqli ()->errno ." ( " .$ this ->mysqli ()->error .") " );
412
+ };
413
+
414
+ // return stmt for future use
415
+ return $ stmt ;
416
+ }
417
+
384
418
/**
385
419
* Execute raw SQL query.
386
420
*
@@ -864,6 +898,123 @@ public function join($joinTable, $joinCondition, $joinType = '')
864
898
865
899
return $ this ;
866
900
}
901
+
902
+
903
+ /**
904
+ * This is a basic method which allows you to import raw .CSV data into a table
905
+ * Please check out http://dev.mysql.com/doc/refman/5.7/en/load-data.html for a valid .csv file.
906
+
907
+ * @author Jonas Barascu (Noneatme)
908
+ * @param string $importTable The database table where the data will be imported into.
909
+ * @param string $importFile The file to be imported. Please use double backslashes \\ and make sure you
910
+ * @param string $importSettings An Array defining the import settings as described in the README.md
911
+ * @return boolean
912
+ */
913
+ public function loadData ($ importTable , $ importFile , $ importSettings = null )
914
+ {
915
+ // We have to check if the file exists
916
+ if (!file_exists ($ importFile )) {
917
+ // Throw an exception
918
+ throw new Exception ("importCSV -> importFile " .$ importFile ." does not exists! " );
919
+ return ;
920
+ }
921
+
922
+ // Define the default values
923
+ // We will merge it later
924
+ $ settings = Array ("fieldChar " => '; ' , "lineChar " => PHP_EOL , "linesToIgnore " => 1 );
925
+
926
+ // Check the import settings
927
+ if (gettype ($ importSettings ) == "array " ) {
928
+ // Merge the default array with the custom one
929
+ $ settings = array_merge ($ settings , $ importSettings );
930
+ }
931
+
932
+ // Add the prefix to the import table
933
+ $ table = self ::$ prefix . $ importTable ;
934
+
935
+ // Add 1 more slash to every slash so maria will interpret it as a path
936
+ $ importFile = str_replace ("\\" , "\\\\" , $ importFile );
937
+
938
+ // Build SQL Syntax
939
+ $ sqlSyntax = sprintf ('LOAD DATA INFILE \'%s \' INTO TABLE %s ' ,
940
+ $ importFile , $ table );
941
+
942
+ // FIELDS
943
+ $ sqlSyntax .= sprintf (' FIELDS TERMINATED BY \'%s \'' , $ settings ["fieldChar " ]);
944
+ if (isset ($ settings ["fieldEnclosure " ])) {
945
+ $ sqlSyntax .= sprintf (' ENCLOSED BY \'%s \'' , $ settings ["fieldEnclosure " ]);
946
+ }
947
+
948
+ // LINES
949
+ $ sqlSyntax .= sprintf (' LINES TERMINATED BY \'%s \'' , $ settings ["lineChar " ]);
950
+ if (isset ($ settings ["lineStarting " ])) {
951
+ $ sqlSyntax .= sprintf (' STARTING BY \'%s \'' , $ settings ["lineStarting " ]);
952
+ }
953
+
954
+ // IGNORE LINES
955
+ $ sqlSyntax .= sprintf (' IGNORE %d LINES ' , $ settings ["linesToIgnore " ]);
956
+
957
+ // Exceute the query unprepared because LOAD DATA only works with unprepared statements.
958
+ $ result = $ this ->queryUnprepared ($ sqlSyntax );
959
+
960
+ // Are there rows modified?
961
+ // Let the user know if the import failed / succeeded
962
+ return (bool ) $ result ;
963
+ }
964
+
965
+ /**
966
+ * This method is usefull for importing XML files into a specific table.
967
+ * Check out the LOAD XML syntax for your MySQL server.
968
+ *
969
+ * @author Jonas Barascu
970
+ * @param string $importTable The table in which the data will be imported to.
971
+ * @param string $importFile The file which contains the .XML data.
972
+ * @param string $importSettings An Array defining the import settings as described in the README.md
973
+ *
974
+ * @return boolean Returns true if the import succeeded, false if it failed.
975
+ */
976
+ public function loadXml ($ importTable , $ importFile , $ importSettings = null )
977
+ {
978
+ // We have to check if the file exists
979
+ if (!file_exists ($ importFile )) {
980
+ // Does not exists
981
+ throw new Exception ("loadXml: Import file does not exists " );
982
+ return ;
983
+ }
984
+
985
+ // Create default values
986
+ $ settings = Array ("linesToIgnore " => 0 );
987
+
988
+ // Check the import settings
989
+ if (gettype ($ importSettings ) == "array " ) {
990
+ $ settings = array_merge ($ settings , $ importSettings );
991
+ }
992
+
993
+ // Add the prefix to the import table
994
+ $ table = self ::$ prefix . $ importTable ;
995
+
996
+ // Add 1 more slash to every slash so maria will interpret it as a path
997
+ $ importFile = str_replace ("\\" , "\\\\" , $ importFile );
998
+
999
+ // Build SQL Syntax
1000
+ $ sqlSyntax = sprintf ('LOAD XML INFILE \'%s \' INTO TABLE %s ' ,
1001
+ $ importFile , $ table );
1002
+
1003
+ // FIELDS
1004
+ if (isset ($ settings ["rowTag " ])) {
1005
+ $ sqlSyntax .= sprintf (' ROWS IDENTIFIED BY \'%s \'' , $ settings ["rowTag " ]);
1006
+ }
1007
+
1008
+ // IGNORE LINES
1009
+ $ sqlSyntax .= sprintf (' IGNORE %d LINES ' , $ settings ["linesToIgnore " ]);
1010
+
1011
+ // Exceute the query unprepared because LOAD XML only works with unprepared statements.
1012
+ $ result = $ this ->queryUnprepared ($ sqlSyntax );
1013
+
1014
+ // Are there rows modified?
1015
+ // Let the user know if the import failed / succeeded
1016
+ return (bool ) $ result ;
1017
+ }
867
1018
868
1019
/**
869
1020
* This method allows you to specify multiple (method chaining optional) ORDER BY statements for SQL queries.
@@ -921,7 +1072,123 @@ public function groupBy($groupByField)
921
1072
$ this ->_groupBy [] = $ groupByField ;
922
1073
return $ this ;
923
1074
}
924
-
1075
+
1076
+
1077
+ /**
1078
+ * This method sets the current table lock method.
1079
+ *
1080
+ * @author Jonas Barascu
1081
+ * @param string $method The table lock method. Can be READ or WRITE.
1082
+ *
1083
+ * @throws Exception
1084
+ * @return MysqliDb
1085
+ */
1086
+ public function setLockMethod ($ method )
1087
+ {
1088
+ // Switch the uppercase string
1089
+ switch (strtoupper ($ method )) {
1090
+ // Is it READ or WRITE?
1091
+ case "READ " || "WRITE " :
1092
+ // Succeed
1093
+ $ this ->_tableLockMethod = $ method ;
1094
+ break ;
1095
+ default :
1096
+ // Else throw an exception
1097
+ throw new Exception ("Bad lock type: Can be either READ or WRITE " );
1098
+ break ;
1099
+ }
1100
+ return $ this ;
1101
+ }
1102
+
1103
+ /**
1104
+ * Locks a table for R/W action.
1105
+ *
1106
+ * @author Jonas Barascu
1107
+ * @param string $table The table to be locked. Can be a table or a view.
1108
+ *
1109
+ * @throws Exception
1110
+ * @return MysqliDb if succeeeded;
1111
+ */
1112
+ public function lock ($ table )
1113
+ {
1114
+ // Main Query
1115
+ $ this ->_query = "LOCK TABLES " ;
1116
+
1117
+ // Is the table an array?
1118
+ if (gettype ($ table ) == "array " ) {
1119
+ // Loop trough it and attach it to the query
1120
+ foreach ($ table as $ key => $ value ) {
1121
+ if (gettype ($ value ) == "string " ) {
1122
+ if ($ key > 0 ) {
1123
+ $ this ->_query .= ", " ;
1124
+ }
1125
+ $ this ->_query .= " " .self ::$ prefix .$ value ." " .$ this ->_tableLockMethod ;
1126
+ }
1127
+ }
1128
+ }
1129
+ else {
1130
+ // Build the table prefix
1131
+ $ table = self ::$ prefix . $ table ;
1132
+
1133
+ // Build the query
1134
+ $ this ->_query = "LOCK TABLES " .$ table ." " .$ this ->_tableLockMethod ;
1135
+ }
1136
+
1137
+ // Exceute the query unprepared because LOCK only works with unprepared statements.
1138
+ $ result = $ this ->queryUnprepared ($ this ->_query );
1139
+
1140
+ // Reset the query
1141
+ $ this ->reset ();
1142
+
1143
+ // Are there rows modified?
1144
+ if ($ result ) {
1145
+ // Return true
1146
+ // We can't return ourself because if one table gets locked, all other ones get unlocked!
1147
+ return true ;
1148
+ }
1149
+ // Something went wrong
1150
+ else {
1151
+ throw new Exception ("Locking of table " .$ table ." failed " );
1152
+ }
1153
+
1154
+ // Return the success value
1155
+ return false ;
1156
+ }
1157
+
1158
+ /**
1159
+ * Unlocks all tables in a database.
1160
+ * Also commits transactions.
1161
+ *
1162
+ * @author Jonas Barascu
1163
+ * @return MysqliDb
1164
+ */
1165
+ public function unlock ()
1166
+ {
1167
+ // Build the query
1168
+ $ this ->_query = "UNLOCK TABLES " ;
1169
+
1170
+ // Exceute the query unprepared because UNLOCK and LOCK only works with unprepared statements.
1171
+ $ result = $ this ->queryUnprepared ($ this ->_query );
1172
+
1173
+ // Reset the query
1174
+ $ this ->reset ();
1175
+
1176
+ // Are there rows modified?
1177
+ if ($ result ) {
1178
+ // return self
1179
+ return $ this ;
1180
+ }
1181
+ // Something went wrong
1182
+ else {
1183
+ throw new Exception ("Unlocking of tables failed " );
1184
+ }
1185
+
1186
+
1187
+ // Return self
1188
+ return $ this ;
1189
+ }
1190
+
1191
+
925
1192
/**
926
1193
* This methods returns the ID of the last inserted item
927
1194
*
@@ -2017,4 +2284,4 @@ private function conditionToSql($operator, $val) {
2017
2284
}
2018
2285
}
2019
2286
2020
- // END class
2287
+ // END class
0 commit comments