source: trunk/bureau/class/m_mysql.php @ 904

Revision 904, 14.8 KB checked in by benjamin, 7 years ago (diff)

Misc code cleanup and alternc_export follow-up

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 */
36class m_mysql {
37
38  var $server;
39
40  /*---------------------------------------------------------------------------*/
41  /** Constructor
42  * m_mysql([$mid]) Constructeur de la classe m_mysql, initialise le membre concerne
43  */
44  function m_mysql() {
45      $this->server = $GLOBALS['L_MYSQL_HOST'];
46  }
47
48  /* ----------------------------------------------------------------- */
49  /** Hook called by m_quota to obtain the quota managed by this class.
50   * Quota name
51   */
52  function alternc_quota_names() {
53    return "mysql";
54  }
55
56  /*---------------------------------------------------------------------------*/
57  /** Get the list of the database for the current user.
58   * @return array returns an associative array as follow : <br>
59   *  "db" => database name "bck" => backup mode for this db
60   *  "dir" => Backup folder.
61   *  "size" => Size of the database (in bytes)
62   *  Returns FALSE if the user has no database.
63   */
64  function get_dblist() {
65    global $db,$err,$bro,$cuid;
66    $err->log("mysql","get_dblist");
67    $db->query("SELECT login,pass,db, bck_mode, bck_dir FROM db WHERE uid='$cuid';");
68    if (!$db->num_rows()) {
69      $err->raise("mysql",11);
70      return false;
71    }
72    $c=array();
73    while ($db->next_record()) {
74      list($dbu,$dbn)=split_mysql_database_name($db->f("db"));
75      $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"));
76    }
77   
78    /* find the size of each database */
79    foreach ($c as $key => $val) {
80      $c[$key]['size'] = $this->get_db_size($c[$key]['db']);
81    }
82    return $c;
83  }
84
85  /*---------------------------------------------------------------------------*/
86  /** Returns the details of a user's database.
87   * $dbn is the name of the database (after the _) or nothing for the database "$user"
88   * @return array returns an associative array as follow :
89   *  "db" => Name of the database
90   *  "bck" => Current bckup mode
91   *  "dir" => Backup directory
92   *  "size" => Size of the database (in bytes)
93   *  "pass" => Password of the user
94   *  "history" => Number of backup we keep
95   *  "gzip" => Does we compress the dumps ?
96   *  Returns FALSE if the user has no database of if the database does not exist.
97   */
98  function get_mysql_details($dbn) {
99    global $db,$err,$bro,$mem,$cuid;
100    $root="/var/alternc/html/".substr($mem->user["login"],0,1)."/".$mem->user["login"];
101    $err->log("mysql","get_mysql_details");
102    $dbname=$mem->user["login"].($dbn?"_":"").$dbn;
103    $size=$this->get_db_size($dbname);
104    $db->query("SELECT login,pass,db, bck_mode, bck_gzip, bck_dir, bck_history FROM db WHERE uid='$cuid' AND db='$dbname';");
105    if (!$db->num_rows()) {
106      $err->raise("mysql",4);
107      return array("enabled"=>false);
108    }
109    $c=array();
110    $db->next_record();
111    list($dbu,$dbn)=split_mysql_database_name($db->f("db"));
112    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"));
113  }
114
115  /*---------------------------------------------------------------------------*/
116  /** Create a new database for the current user.
117   * @param $dbn string Database name ($user_$dbn is the mysql db name)
118   * @return TRUE if the database $user_$db has been successfully created, or FALSE if
119   * an error occured, such as over quota user.
120   */
121  function add_db($dbn) {
122    global $db,$err,$quota,$mem,$cuid;
123    $err->log("mysql","add_db",$dbn);
124    if (!$quota->cancreate("mysql")) {
125      $err->raise("mysql",1);
126      return false;
127    }
128    if (!ereg("^[0-9a-z]*$",$dbn)) {
129      $err->raise("mysql",2);
130      return false;
131    }
132    $dbname=$mem->user["login"].($dbn?"_":"").$dbn;
133    if (strlen($dbname) > 64) {
134      $err->raise("mysql",12);
135      return false;
136    }
137    $db->query("SELECT * FROM db WHERE db='$dbname';");
138    if ($db->num_rows()) {
139      $err->raise("mysql",3);
140      return false;
141    }
142    // find the login/pass for this user :
143    $db->query("SELECT login,pass FROM db WHERE uid='$cuid' LIMIT 0,1;");
144    if (!$db->num_rows()) {
145      $lo=$mem->user["uid"];
146      $pa="";
147    } else {
148      $db->next_record();
149      $lo=addslashes($db->f("login"));
150      $pa=addslashes($db->f("pass"));
151    }
152    // Ok, database does not exist, quota is ok and dbname is compliant. Let's proceed
153    $db->query("INSERT INTO db (uid,login,pass,db,bck_mode) VALUES ('$cuid','$lo','$pa','$dbname',0);");
154    // give everything but GRANT on db.*
155    // we assume there's already a user
156    $db->query("GRANT ALL PRIVILEGES ON `".$dbname."`.* TO '".$lo."'@'".$L_MYSQL_CLIENT."'");
157    $db->query("CREATE DATABASE $dbname;");
158    return true;
159  }
160
161  /*---------------------------------------------------------------------------*/
162  /** Delete a database for the current user.
163   * @param $dbn string Name of the database to delete. The db name is $user_$dbn
164   * @return TRUE if the database $user_$db has been successfully deleted, or FALSE if
165   *  an error occured, such as db does not exist.
166   */
167  function del_db($dbn) {
168    global $db,$err,$mem,$cuid;
169    $err->log("mysql","del_db",$dbn);
170    if (!ereg("^[0-9a-z]*$",$dbn)) {
171      $err->raise("mysql",2);
172      return false;
173    }
174    $dbname=$mem->user["login"].($dbn?"_":"").$dbn;
175    $db->query("SELECT login FROM db WHERE db='$dbname';");
176    if (!$db->num_rows()) {
177      $err->raise("mysql",4);
178      return false;
179    }
180    $db->next_record();
181    $login=$db->f("login");
182
183    // Ok, database exists and dbname is compliant. Let's proceed
184    $db->query("DELETE FROM db WHERE uid='$cuid' AND db='$dbname';");
185    $db->query("DROP DATABASE $dbname;");
186    $db->query("SELECT COUNT(*) AS cnt FROM db WHERE uid='$cuid';");
187    $db->next_record();
188    $db->query("REVOKE ALL PRIVILEGES ON `".$dbname."`.* FROM '".$login."'@'%'");
189    if ($db->f("cnt")==0) {
190      $db->query("DELETE FROM mysql.user WHERE User='".$login."';");
191      $db->query("FLUSH PRIVILEGES;");
192    }
193    return true;
194  }
195 
196  /*---------------------------------------------------------------------------*/
197  /** Set the backup parameters for the database $db
198   * @param $db string database name
199   * @param $bck_mode integer Backup mode (0 = none 1 = daily 2 = weekly)
200   * @param $bck_history integer How many backup should we keep ?
201   * @param $bck_gzip boolean shall we compress the backup ?
202   * @param $bck_dir string Directory relative to the user account where the backup will be stored
203   * @return boolean true if the backup parameters has been successfully changed, false if not.
204   */
205  function put_mysql_backup($dbn,$bck_mode,$bck_history,$bck_gzip,$bck_dir) {
206    global $db,$err,$mem,$bro,$cuid;
207    $err->log("mysql","put_mysql_backup");
208    if (!ereg("^[0-9a-z]*$",$dbn)) {
209      $err->raise("mysql",2);
210      return false;
211    }
212    $dbname=$mem->user["login"].($dbn?"_":"").$dbn;
213    $db->query("SELECT * FROM db WHERE uid='$cuid' AND db='$dbname';");
214    if (!$db->num_rows()) {
215      $err->raise("mysql",4);
216      return false;
217    }
218    $db->next_record();
219    $bck_mode=intval($bck_mode);
220    $bck_history=intval($bck_history);
221    if ($bck_gzip)
222      $bck_gzip="1";
223    else
224      $bck_gzip="0";
225    if (!$bck_mode)
226      $bck_mode="0";
227    if (!$bck_history) {
228      $err->raise("mysql",5);
229      return false;
230    }
231    if (($bck_dir=$bro->convertabsolute($bck_dir,0))===false) { // return a full path or FALSE
232      $err->raise("mysql",6);
233      return false;
234    }
235    $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';");
236    return true;
237  }
238
239  /*---------------------------------------------------------------------------*/
240  /** Change the password of the user in MySQL
241   * @param $password string new password (cleartext)
242   * @return boolean TRUE if the password has been successfully changed, FALSE else.
243   */
244  function put_mysql_details($password) {
245    global $db,$err,$mem,$cuid;
246    $err->log("mysql","put_mysql_details");
247    $db->query("SELECT * FROM db WHERE uid='$cuid';");
248    if (!$db->num_rows()) {
249      $err->raise("mysql",7);
250      return false;
251    }
252    $db->next_record();
253    $login=$db->f("login");
254
255    if (strlen($password)>16) {
256      $err->raise("mysql",8);
257      return false;
258    }
259    // Update all the "pass" fields for this user :
260    $db->query("UPDATE db SET pass='$password' WHERE uid='$cuid';");
261    $db->query("SET PASSWORD FOR '$login'@'%' = PASSWORD('$password')");
262    return true;
263  }
264
265  /* ----------------------------------------------------------------- */
266  /** Create a new mysql account for this user
267   * @param string cleartext password for the new account
268   * It also create the first database.
269   */
270  function new_mysql($password) {
271    global $db,$err,$mem,$cuid;
272    $err->log("mysql","new_mysql");
273    if (strlen($password)>16) {
274      $err->raise("mysql",8);
275      return false;
276    }
277    $db->query("SELECT * FROM db WHERE uid='$cuid';");
278    if ($db->num_rows()) {
279      $err->raise("mysql",10);
280      return false;
281    }
282    $login=$mem->user["uid"];
283    $dbname=$mem->user["login"];
284    // OK, creation now...
285    $db->query("INSERT INTO db (uid,login,pass,db) VALUES ('$cuid','".$login."','$password','".$dbname."');");
286    // give everything but GRANT on $user.*
287    $db->query("GRANT ALL PRIVILEGES ON `".$dbname."`.* TO '".$login."'@'".$L_MYSQL_CLIENT."' IDENTIFIED BY '".$password."'");
288    $db->query("CREATE DATABASE ".$dbname.";");
289    return true;
290  }
291
292
293  /* ----------------------------------------------------------------- */
294  /** Restore a sql backup script on a user's database.
295   * <b>TODO : </b> Add a parameter to choose which database to restore.
296   */
297  function restore($file,$stdout,$r) {
298    global $err,$bro,$mem,$L_MYSQL_HOST;
299    if (!($fi=$bro->convertabsolute($file,0))) {
300      $err->raise("mysql",9);
301    }
302    if (substr($fi,-3)==".gz") {
303      $exe="/bin/gzip -d -c <\"$fi\" | /usr/bin/mysql -h".$L_MYSQL_HOST." -u".$r["login"]." -p".$r["pass"]." ".$r["db"];
304    } else {
305      $exe="/usr/bin/mysql -h".$L_MYSQL_HOST." -u".$r["login"]." -p".$r["pass"]." ".$r["db"]." <".$fi;
306    }
307    $exe .= " 2>&1";
308   
309    echo "<code><pre>" ;
310    if ($stdout) {
311      passthru($exe,$ret);
312    } else {
313      exec ($exe,$ret);
314    }
315    echo "</pre></code>" ;
316    if ($ret != 0) {
317      return false ;
318    } else {
319      return true ;
320    }
321  }
322 
323  /* ----------------------------------------------------------------- */
324  /** Get size of a database
325   * @param $dbname name of the database
326   * @return integer database size
327   * @access private
328   */
329 function get_db_size($dbname) {
330   global $db,$err;
331
332   $db->query("SHOW TABLE STATUS FROM `$dbname`;");
333   $size = 0;
334   while ($db->next_record()) {
335     $size += $db->f('Data_length') + $db->f('Index_length')
336              + $db->f('Data_free');
337   }
338   return $size;
339 }
340 
341  /* ----------------------------------------------------------------- */
342  /** Hook function called by the quota class to compute user used quota
343   * Returns the used quota for the $name service for the current user.
344   * @param $name string name of the quota
345   * @return integer the number of service used or false if an error occured
346   * @access private
347   */
348  function alternc_get_quota($name) {
349    global $err,$db,$cuid;
350    if ($name=="mysql") {
351      $err->log("mysql","alternc_get_quota");
352      $c=$this->get_dblist();
353      if (is_array($c)) {
354        return count($c);
355      } else {
356        return 0;
357      }
358    } else return false;
359  }
360
361
362  /* ----------------------------------------------------------------- */
363  /** Hook function called when a user is deleted.
364   * AlternC's standard function that delete a member
365   */
366  function alternc_del_member() {
367    global $db,$err,$cuid;
368    $err->log("mysql","alternc_del_member");
369    $c=$this->get_dblist();
370    if (is_array($c)) {
371      for($i=0;$i<count($c);$i++) {
372        $this->del_db($c[$i]["name"]);
373      }
374    }
375    return true;
376  }
377
378
379  /* ----------------------------------------------------------------- */
380  /**
381   * Exporte toutes les informations mysql du compte.
382   * @access private
383   * EXPERIMENTAL 'sid' function ;)
384   */
385  function alternc_export($tmpdir) {
386    global $db,$err,$cuid;
387    $err->log("mysql","export");
388    $db->query("SELECT login, pass, db, bck_mode, bck_dir, bck_history, bck_gzip FROM db WHERE uid='$cuid';");
389    if ($db->next_record()) {
390      $str="<mysql>\n";
391      $str.="  <login>".xml_entities($db->Record["login"])."</login>";
392      $str.="  <pass>".xml_entities($db->Record["pass"])."</pass>";
393      do {
394        // Do the dump :
395        $filename=$tmpdir."/mysql.".$db->Record["db"].".sql.gz";
396        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));
397        $str.="  <db>\n";
398        $str.="    <name>".xml_entities($db->Record["db"])."</name>\n";
399        if ($s["bck_mode"]!=0) {
400          $str.="    <backup>\n";
401          $str.="      <mode>".xml_entities($db->Record["bck_mode"])."</mode>\n";
402          $str.="      <dir>".xml_entities($db->Record["bck_dir"])."</dir>\n";
403          $str.="      <history>".xml_entities($db->Record["bck_history"])."</history>\n";
404          $str.="      <gzip>".xml_entities($db->Record["bck_gzip"])."</gzip>\n";
405          $str.="    </backup>\n";
406        }
407        $str.="  </db>\n";
408      } while ($db->next_record());
409      $str.="</mysql>\n";
410    }
411    return $str;
412  }
413
414
415} /* Class m_mysql */
416
417?>
Note: See TracBrowser for help on using the repository browser.