root/alternc/trunk/bureau/class/m_mysql.php

Revision 2076, 21.1 kB (checked in by anarcat, 8 months ago)

add a alternc_del_session() hook that removes the phpMyAdmin cookie on logout

Closes: #1082

Line 
1 <?php
2 /*
3  $Id: m_mysql.php,v 1.35 2005/12/18 09:51:32 benjamin Exp $
4  ----------------------------------------------------------------------
5  AlternC - Web Hosting System
6  Copyright (C) 2002 by the AlternC Development Team.
7  http://alternc.org/
8  ----------------------------------------------------------------------
9  Based on:
10  Valentin Lacambre's web hosting softwares: http://altern.org/
11  ----------------------------------------------------------------------
12  LICENSE
13
14  This program is free software; you can redistribute it and/or
15  modify it under the terms of the GNU General Public License (GPL)
16  as published by the Free Software Foundation; either version 2
17  of the License, or (at your option) any later version.
18
19  This program is distributed in the hope that it will be useful,
20  but WITHOUT ANY WARRANTY; without even the implied warranty of
21  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  GNU General Public License for more details.
23
24  To read the license please visit http://www.gnu.org/copyleft/gpl.html
25  ----------------------------------------------------------------------
26  Original Author of file: Benjamin Sonntag
27  Purpose of file: Manage mysql database for users.
28  ----------------------------------------------------------------------
29 */
30 /**
31  * MySQL user database management for AlternC.
32  * This class manage user's databases in MySQL, and user's MySQL accounts.
33  *
34  * @copyright    AlternC-Team 2002-2005 http://alternc.org/
35  */
36 class m_mysql {
37
38   var $server;
39   var $client;
40
41   /*---------------------------------------------------------------------------*/
42   /** Constructor
43   * m_mysql([$mid]) Constructeur de la classe m_mysql, initialise le membre concerne
44   */
45   function m_mysql() {
46       $this->server = $GLOBALS['L_MYSQL_HOST'];
47       $this->client = $GLOBALS['L_MYSQL_CLIENT'];
48   }
49
50   /* ----------------------------------------------------------------- */
51   /** Hook called by m_quota to obtain the quota managed by this class.
52    * Quota name
53    */
54   function alternc_quota_names() {
55     return array("mysql","mysql_users");
56   }
57
58   /*---------------------------------------------------------------------------*/
59   /** Get the list of the database for the current user.
60    * @return array returns an associative array as follow : <br>
61    *  "db" => database name "bck" => backup mode for this db
62    *  "dir" => Backup folder.
63    *  "size" => Size of the database (in bytes)
64    *  Returns FALSE if the user has no database.
65    */
66   function get_dblist() {
67     global $db,$err,$bro,$cuid;
68     $err->log("mysql","get_dblist");
69     $db->query("SELECT login,pass,db, bck_mode, bck_dir FROM db WHERE uid='$cuid';");
70     if (!$db->num_rows()) {
71       $err->raise("mysql",11);
72       return false;
73     }
74     $c=array();
75     while ($db->next_record()) {
76       list($dbu,$dbn)=split_mysql_database_name($db->f("db"));
77       $c[]=array("db"=>$db->f("db"), "name"=>$dbn,"bck"=>$db->f("bck_mode"), "dir"=>$db->f("bck_dir"), "login"=>$db->f("login"), "pass"=>$db->f("pass"));
78     }
79     
80     /* find the size of each database */
81     foreach ($c as $key => $val) {
82       $c[$key]['size'] = $this->get_db_size($c[$key]['db']);
83     }
84     return $c;
85   }
86
87   /*---------------------------------------------------------------------------*/
88   /** Returns the details of a user's database.
89    * $dbn is the name of the database (after the _) or nothing for the database "$user"
90    * @return array returns an associative array as follow :
91    *  "db" => Name of the database
92    *  "bck" => Current bckup mode
93    *  "dir" => Backup directory
94    *  "size" => Size of the database (in bytes)
95    *  "pass" => Password of the user
96    *  "history" => Number of backup we keep
97    *  "gzip" => Does we compress the dumps ?
98    *  Returns FALSE if the user has no database of if the database does not exist.
99    */
100   function get_mysql_details($dbn) {
101     global $db,$err,$bro,$mem,$cuid;
102     $root="/var/alternc/html/".substr($mem->user["login"],0,1)."/".$mem->user["login"];
103     $err->log("mysql","get_mysql_details");
104     $dbname=$mem->user["login"].($dbn?"_":"").$dbn;
105     $size=$this->get_db_size($dbname);
106     $db->query("SELECT login,pass,db, bck_mode, bck_gzip, bck_dir, bck_history FROM db WHERE uid='$cuid' AND db='$dbname';");
107     if (!$db->num_rows()) {
108       $err->raise("mysql",4);
109       return array("enabled"=>false);
110     }
111     $c=array();
112     $db->next_record();
113     list($dbu,$dbn)=split_mysql_database_name($db->f("db"));
114     return array("enabled"=>true,"login"=>$db->f("login"),"db"=>$db->f("db"), "name"=>$dbn,"bck"=>$db->f("bck_mode"), "dir"=>substr($db->f("bck_dir"),strlen($root)), "size"=>$size, "pass"=>$db->f("pass"), "history"=>$db->f("bck_history"), "gzip"=>$db->f("bck_gzip"));
115   }
116
117   /*---------------------------------------------------------------------------*/
118   /** Create a new database for the current user.
119    * @param $dbn string Database name ($user_$dbn is the mysql db name)
120    * @return TRUE if the database $user_$db has been successfully created, or FALSE if
121    * an error occured, such as over quota user.
122    */
123   function add_db($dbn) {
124     global $db,$err,$quota,$mem,$cuid;
125     $err->log("mysql","add_db",$dbn);
126     if (!$quota->cancreate("mysql")) {
127       $err->raise("mysql",1);
128       return false;
129     }
130     if (!ereg("^[0-9a-z]*$",$dbn)) {
131       $err->raise("mysql",2);
132       return false;
133     }
134     $dbname=$mem->user["login"].($dbn?"_":"").$dbn;
135     if (strlen($dbname) > 64) {
136       $err->raise("mysql",12);
137       return false;
138     }
139     $db->query("SELECT * FROM db WHERE db='$dbname';");
140     if ($db->num_rows()) {
141       $err->raise("mysql",3);
142       return false;
143     }
144     // find the login/pass for this user :
145     $db->query("SELECT login,pass FROM db WHERE uid='$cuid' LIMIT 0,1;");
146     if (!$db->num_rows()) {
147       $lo=$mem->user["login"];
148       $pa="";
149     } else {
150       $db->next_record();
151       $lo=addslashes($db->f("login"));
152       $pa=addslashes($db->f("pass"));
153     }
154     if ($db->query("CREATE DATABASE $dbname;")) {
155       // Ok, database does not exist, quota is ok and dbname is compliant. Let's proceed
156       $db->query("INSERT INTO db (uid,login,pass,db,bck_mode) VALUES ('$cuid','$lo','$pa','$dbname',0);");
157       // give everything but GRANT on db.*
158       // we assume there's already a user
159       $db->query("GRANT ALL PRIVILEGES ON `".$dbname."`.* TO '".$lo."'@'$this->client'");
160       return true;
161     } else {
162       $err->raise("mysql",3);
163       return false;
164     }
165   }
166
167   /*---------------------------------------------------------------------------*/
168   /** Delete a database for the current user.
169    * @param $dbn string Name of the database to delete. The db name is $user_$dbn
170    * @return TRUE if the database $user_$db has been successfully deleted, or FALSE if
171    *  an error occured, such as db does not exist.
172    */
173   function del_db($dbn) {
174     global $db,$err,$mem,$cuid;
175     $err->log("mysql","del_db",$dbn);
176
177     $dbname=addslashes($mem->user["login"].($dbn?"_":"").$dbn);
178     $db->query("SELECT login FROM db WHERE db='$dbname';");
179     if (!$db->num_rows()) {
180       $err->raise("mysql",4);
181       return false;
182     }
183     $db->next_record();
184     $login=$db->f("login");
185
186     // Ok, database exists and dbname is compliant. Let's proceed
187     $db->query("DELETE FROM db WHERE uid='$cuid' AND db='$dbname';");
188     $db->query("DROP DATABASE `$dbname`;");
189     $db->query("SELECT COUNT(*) AS cnt FROM db WHERE uid='$cuid';");
190     $db->next_record();
191     $db->query("REVOKE ALL PRIVILEGES ON `".$dbname."`.* FROM '".$login."'@'$this->client'");
192     if ($db->f("cnt")==0) {
193       $db->query("DELETE FROM mysql.user WHERE User='".$login."';");
194       $db->query("FLUSH PRIVILEGES;");
195     }
196     return true;
197   }
198  
199   /*---------------------------------------------------------------------------*/
200   /** Set the backup parameters for the database $db
201    * @param $db string database name
202    * @param $bck_mode integer Backup mode (0 = none 1 = daily 2 = weekly)
203    * @param $bck_history integer How many backup should we keep ?
204    * @param $bck_gzip boolean shall we compress the backup ?
205    * @param $bck_dir string Directory relative to the user account where the backup will be stored
206    * @return boolean true if the backup parameters has been successfully changed, false if not.
207    */
208   function put_mysql_backup($dbn,$bck_mode,$bck_history,$bck_gzip,$bck_dir) {
209     global $db,$err,$mem,$bro,$cuid;
210     $err->log("mysql","put_mysql_backup");
211     if (!ereg("^[0-9a-z]*$",$dbn)) {
212       $err->raise("mysql",2);
213       return false;
214     }
215     $dbname=$mem->user["login"].($dbn?"_":"").$dbn;
216     $db->query("SELECT * FROM db WHERE uid='$cuid' AND db='$dbname';");
217     if (!$db->num_rows()) {
218       $err->raise("mysql",4);
219       return false;
220     }
221     $db->next_record();
222     $bck_mode=intval($bck_mode);
223     $bck_history=intval($bck_history);
224     if ($bck_gzip)
225       $bck_gzip="1";
226     else
227       $bck_gzip="0";
228     if (!$bck_mode)
229       $bck_mode="0";
230     if (!$bck_history) {
231       $err->raise("mysql",5);
232       return false;
233     }
234     if (($bck_dir=$bro->convertabsolute($bck_dir,0))===false) { // return a full path or FALSE
235       $err->raise("mysql",6);
236       return false;
237     }
238     $db->query("UPDATE db SET bck_mode='$bck_mode', bck_history='$bck_history', bck_gzip='$bck_gzip', bck_dir='$bck_dir' WHERE uid='$cuid' AND db='$dbname';");
239     return true;
240   }
241
242   /*---------------------------------------------------------------------------*/
243   /** Change the password of the user in MySQL
244    * @param $password string new password (cleartext)
245    * @return boolean TRUE if the password has been successfully changed, FALSE else.
246    */
247   function put_mysql_details($password) {
248     global $db,$err,$mem,$cuid;
249     $err->log("mysql","put_mysql_details");
250     $db->query("SELECT * FROM db WHERE uid='$cuid';");
251     if (!$db->num_rows()) {
252       $err->raise("mysql",7);
253       return false;
254     }
255     $db->next_record();
256     $login=$db->f("login");
257
258     if (strlen($password)>16) {
259       $err->raise("mysql",8);
260       return false;
261     }
262     // Update all the "pass" fields for this user :
263     $db->query("UPDATE db SET pass='$password' WHERE uid='$cuid';");
264     $db->query("SET PASSWORD FOR '$login'@'$this->client' = PASSWORD('$password')");
265     return true;
266   }
267
268   /* ----------------------------------------------------------------- */
269   /** Create a new mysql account for this user
270    * @param string cleartext password for the new account
271    * It also create the first database.
272    */
273   function new_mysql($password) {
274     global $db,$err,$mem,$cuid;
275     $err->log("mysql","new_mysql");
276     if (strlen($password)>16) {
277       $err->raise("mysql",8);
278       return false;
279     }
280     $db->query("SELECT * FROM db WHERE uid='$cuid';");
281     if ($db->num_rows()) {
282       $err->raise("mysql",10);
283       return false;
284     }
285     $login=$mem->user["login"];
286     $dbname=$mem->user["login"];
287     // OK, creation now...
288     $db->query("INSERT INTO db (uid,login,pass,db) VALUES ('$cuid','".$login."','$password','".$dbname."');");
289     // give everything but GRANT on $user.*
290     $db->query("GRANT ALL PRIVILEGES ON `".$dbname."`.* TO '".$login."'@'$this->client' IDENTIFIED BY '".$password."'");
291     $db->query("CREATE DATABASE `".$dbname."`;");
292     return true;
293   }
294
295
296   /* ----------------------------------------------------------------- */
297   /** Restore a sql backup script on a user's database.
298    */
299   function restore($file,$stdout,$id) {
300     global $err,$bro,$mem,$L_MYSQL_HOST;
301     if (!$r=$this->get_mysql_details($id)) {
302       return false;
303     }
304     if (!($fi=$bro->convertabsolute($file,0))) {
305       $err->raise("mysql",9);
306       return false;
307     }
308     if (substr($fi,-3)==".gz") {
309       $exe="/bin/gzip -d -c <".escapeshellarg($fi)." | /usr/bin/mysql -h".escapeshellarg($L_MYSQL_HOST)." -u".escapeshellarg($r["login"])." -p".escapeshellarg($r["pass"])." ".escapeshellarg($r["db"]);
310     } elseif (substr($fi,-4)==".bz2") {
311       $exe="/usr/bin/bunzip2 -d -c <".escapeshellarg($fi)." | /usr/bin/mysql -h".escapeshellarg($L_MYSQL_HOST)." -u".escapeshellarg($r["login"])." -p".escapeshellarg($r["pass"])." ".escapeshellarg($r["db"]);
312     } else {
313       $exe="/usr/bin/mysql -h".escapeshellarg($L_MYSQL_HOST)." -u".escapeshellarg($r["login"])." -p".escapeshellarg($r["pass"])." ".escapeshellarg($r["db"])." <".escapeshellarg($fi);
314     }
315     $exe .= " 2>&1";
316     
317     echo "<code><pre>" ;
318     if ($stdout) {
319       passthru($exe,$ret);
320     } else {
321       exec ($exe,$ret);
322     }
323     echo "</pre></code>" ;
324     if ($ret != 0) {
325       return false ;
326     } else {
327       return true ;
328     }
329   }
330  
331   /* ----------------------------------------------------------------- */
332   /** Get size of a database
333    * @param $dbname name of the database
334    * @return integer database size
335    * @access private
336    */
337  function get_db_size($dbname) {
338    global $db,$err;
339
340    $db->query("SHOW TABLE STATUS FROM `$dbname`;");
341    $size = 0;
342    while ($db->next_record()) {
343      $size += $db->f('Data_length') + $db->f('Index_length')
344               + $db->f('Data_free');
345    }
346    return $size;
347  }
348  
349   /* ----------------------------------------------------------------- */
350   /** Hook function called by the quota class to compute user used quota
351    * Returns the used quota for the $name service for the current user.
352    * @param $name string name of the quota
353    * @return integer the number of service used or false if an error occured
354    * @access private
355    */
356   function alternc_get_quota($name) {
357     global $err,$db,$cuid;
358     if ($name=="mysql") {
359       $err->log("mysql","alternc_get_quota");
360       $c=$this->get_dblist();
361       if (is_array($c)) {
362     return count($c);
363       } else {
364     return 0;
365       }
366     } elseif ($name=="mysql_users") {
367       $err->log("mysql","alternc_get_quota");
368       $c=$this->get_userslist();
369       if(is_array($c))
370         return count($c);
371       else
372         return 0;
373     } else return false;
374   }
375
376
377   /* ----------------------------------------------------------------- */
378   /** Hook function called when a user is deleted.
379    * AlternC's standard function that delete a member
380    */
381   function alternc_del_member() {
382     global $db,$err,$cuid;
383     $err->log("mysql","alternc_del_member");
384     $c=$this->get_dblist();
385     if (is_array($c)) {
386       for($i=0;$i<count($c);$i++) {
387     $this->del_db($c[$i]["name"]);
388       }
389     }
390     return true;
391   }
392
393   /* ----------------------------------------------------------------- */
394   /** Hook function called when a user is logged out.
395    * We just remove the cookie created in admin/sql_admin.php
396    */
397   function alternc_del_session() {
398       setcookie("REMOTE_USER","");
399       setcookie("REMOTE_PASSWORD","");
400   }
401
402   /* ----------------------------------------------------------------- */
403   /**
404    * Exporte toutes les informations mysql du compte.
405    * @access private
406    * EXPERIMENTAL 'sid' function ;)
407    */
408   function alternc_export($tmpdir) {
409     global $db,$err,$cuid;
410     $err->log("mysql","export");
411     $db->query("SELECT login, pass, db, bck_mode, bck_dir, bck_history, bck_gzip FROM db WHERE uid='$cuid';");
412     if ($db->next_record()) {
413       $str="<mysql>\n";
414       $str.="  <login>".xml_entities($db->Record["login"])."</login>";
415       $str.="  <pass>".xml_entities($db->Record["pass"])."</pass>";
416       do {
417     // Do the dump :
418     $filename=$tmpdir."/mysql.".$db->Record["db"].".sql.gz";
419     exec("/usr/bin/mysqldump --add-drop-table --allow-keywords -Q -f -q -a -e -u".escapeshellarg($db->Record["login"])." -p".escapeshellarg($db->Record["pass"])." ".escapeshellarg($db->Record["db"])." |/bin/gzip >".escapeshellarg($filename));
420     $str.="  <db>\n";
421     $str.="    <name>".xml_entities($db->Record["db"])."</name>\n";
422     if ($s["bck_mode"]!=0) {
423       $str.="    <backup>\n";
424       $str.="      <mode>".xml_entities($db->Record["bck_mode"])."</mode>\n";
425       $str.="      <dir>".xml_entities($db->Record["bck_dir"])."</dir>\n";
426       $str.="      <history>".xml_entities($db->Record["bck_history"])."</history>\n";
427       $str.="      <gzip>".xml_entities($db->Record["bck_gzip"])."</gzip>\n";
428       $str.="    </backup>\n";
429     }
430     $str.="  </db>\n";
431       } while ($db->next_record());
432       $str.="</mysql>\n";
433     }
434     return $str;
435   }
436
437   function get_userslist() {
438     global $db,$err,$bro,$cuid;
439     $err->log("mysql","get_userslist");
440     $db->query("SELECT name FROM dbusers WHERE uid='$cuid';");
441     if (!$db->num_rows()) {
442       $err->raise("mysql",19);
443       return false;
444     }
445     $c=array();
446     while ($db->next_record()) {
447       $c[]=array("name"=>substr($db->f("name"),strpos($db->f("name"),"_")+1));
448     }
449
450     return $c;
451   }
452
453   function add_user($usern,$password,$passconf) {
454     global $db,$err,$quota,$mem,$cuid;
455     $err->log("mysql","add_user",$usern);
456     
457     $user=addslashes($mem->user["login"]."_$usern");
458     $pass=addslashes($password);
459         
460     if (!$quota->cancreate("mysql_users")) {
461       $err->raise("mysql",13);
462       return false;
463     }
464     if (!ereg("^[0-9a-z]",