mirror of
https://github.com/moodle/moodle.git
synced 2025-08-05 08:56:36 +02:00

Petri Asikainen rewrote insert_record to use ADOdb functions. It might be very slightly slower but it gets rid of all the horrible not-quite-working PostgreSQL workarounds the old one contained. It worked for him on PostgreSQL 7.4 and for me on MySQL 3.23 and 4.0.15, so I'm checking it in. Please test it thoroughly on your test systems. Since it writes data it has the potential to stuff things up, so be careful on production systems for a few days.
2200 lines
61 KiB
PHP
2200 lines
61 KiB
PHP
<?PHP // $Id$
|
|
|
|
/// FUNCTIONS FOR DATABASE HANDLING ////////////////////////////////
|
|
/**
|
|
* execute a given sql command string
|
|
*
|
|
* Completely general function - it just runs some SQL and reports success.
|
|
*
|
|
* @param type description
|
|
*/
|
|
function execute_sql($command, $feedback=true) {
|
|
/// Completely general function - it just runs some SQL and reports success.
|
|
|
|
global $db;
|
|
|
|
$result = $db->Execute("$command");
|
|
|
|
if ($result) {
|
|
if ($feedback) {
|
|
echo "<P><FONT COLOR=green><B>".get_string("success")."</B></FONT></P>";
|
|
}
|
|
return true;
|
|
} else {
|
|
if ($feedback) {
|
|
echo "<P><FONT COLOR=red><B>".get_string("error")."</B></FONT></P>";
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
/**
|
|
* Run an arbitrary sequence of semicolon-delimited SQL commands
|
|
*
|
|
* Assumes that the input text (file or string consists of
|
|
* a number of SQL statements ENDING WITH SEMICOLONS. The
|
|
* semicolons MUST be the last character in a line.
|
|
* Lines that are blank or that start with "#" are ignored.
|
|
* Only tested with mysql dump files (mysqldump -p -d moodle)
|
|
*
|
|
* @param type description
|
|
*/
|
|
|
|
function modify_database($sqlfile="", $sqlstring="") {
|
|
|
|
global $CFG;
|
|
|
|
$success = true; // Let's be optimistic :-)
|
|
|
|
if (!empty($sqlfile)) {
|
|
if (!is_readable($sqlfile)) {
|
|
$success = false;
|
|
echo "<P>Tried to modify database, but \"$sqlfile\" doesn't exist!</P>";
|
|
return $success;
|
|
} else {
|
|
$lines = file($sqlfile);
|
|
}
|
|
} else {
|
|
$lines[] = $sqlstring;
|
|
}
|
|
|
|
$command = "";
|
|
|
|
foreach ($lines as $line) {
|
|
$line = rtrim($line);
|
|
$length = strlen($line);
|
|
|
|
if ($length and $line[0] <> "#") {
|
|
if (substr($line, $length-1, 1) == ";") {
|
|
$line = substr($line, 0, $length-1); // strip ;
|
|
$command .= $line;
|
|
$command = str_replace("prefix_", $CFG->prefix, $command); // Table prefixes
|
|
if (! execute_sql($command)) {
|
|
$success = false;
|
|
}
|
|
$command = "";
|
|
} else {
|
|
$command .= $line;
|
|
}
|
|
}
|
|
}
|
|
|
|
return $success;
|
|
|
|
}
|
|
|
|
/// FUNCTIONS TO MODIFY TABLES ////////////////////////////////////////////
|
|
|
|
/**
|
|
* Add a new field to a table, or modify an existing one (if oldfield is defined).
|
|
*
|
|
* Add a new field to a table, or modify an existing one (if oldfield is defined).
|
|
*
|
|
* @param type description
|
|
*/
|
|
|
|
function table_column($table, $oldfield, $field, $type="integer", $size="10",
|
|
$signed="unsigned", $default="0", $null="not null", $after="") {
|
|
global $CFG, $db;
|
|
|
|
switch (strtolower($CFG->dbtype)) {
|
|
|
|
case "mysql":
|
|
case "mysqlt":
|
|
|
|
switch (strtolower($type)) {
|
|
case "text":
|
|
$type = "TEXT";
|
|
$signed = "";
|
|
break;
|
|
case "integer":
|
|
$type = "INTEGER($size)";
|
|
break;
|
|
case "varchar":
|
|
$type = "VARCHAR($size)";
|
|
$signed = "";
|
|
break;
|
|
}
|
|
|
|
if (!empty($oldfield)) {
|
|
$operation = "CHANGE $oldfield $field";
|
|
} else {
|
|
$operation = "ADD $field";
|
|
}
|
|
|
|
$default = "DEFAULT '$default'";
|
|
|
|
if (!empty($after)) {
|
|
$after = "AFTER `$after`";
|
|
}
|
|
|
|
return execute_sql("ALTER TABLE {$CFG->prefix}$table $operation $type $signed $default $null $after");
|
|
break;
|
|
|
|
case "postgres7": // From Petri Asikainen
|
|
//Check db-version
|
|
$dbinfo = $db->ServerInfo();
|
|
$dbver = substr($dbinfo['version'],0,3);
|
|
|
|
//to prevent conflicts with reserved words
|
|
$field = "\"$field\"";
|
|
$oldfield = "\"$oldfield\"";
|
|
|
|
switch (strtolower($type)) {
|
|
case "integer":
|
|
if ($size <= 2) {
|
|
$type = "INT2";
|
|
}
|
|
if ($size <= 4) {
|
|
$type = "INT";
|
|
}
|
|
if ($size > 4) {
|
|
$type = "INT8";
|
|
}
|
|
break;
|
|
case "varchar":
|
|
$type = "VARCHAR($size)";
|
|
break;
|
|
}
|
|
|
|
$default = "'$default'";
|
|
|
|
//After is not implemented in postgesql
|
|
//if (!empty($after)) {
|
|
// $after = "AFTER '$after'";
|
|
//}
|
|
|
|
if ($oldfield != "\"\"") {
|
|
if ($field != $oldfield) {
|
|
execute_sql("ALTER TABLE {$CFG->prefix}$table RENAME COLUMN $oldfield TO $field");
|
|
}
|
|
} else {
|
|
execute_sql("ALTER TABLE {$CFG->prefix}$table ADD COLUMN $field $type");
|
|
execute_sql("UPDATE {$CFG->prefix}$table SET $field=$default");
|
|
}
|
|
|
|
if ($dbver >= "7.3") {
|
|
// modifying 'not null' is posible before 7.3
|
|
//update default values to table
|
|
if ($null == "NOT NULL") {
|
|
execute_sql("UPDATE {$CFG->prefix}$table SET $field=$default where $field IS NULL");
|
|
execute_sql("ALTER TABLE {$CFG->prefix}$table ALTER COLUMN $field SET $null");
|
|
} else {
|
|
execute_sql("ALTER TABLE {$CFG->prefix}$table ALTER COLUMN $field DROP NOT NULL");
|
|
}
|
|
}
|
|
|
|
return execute_sql("ALTER TABLE {$CFG->prefix}$table ALTER COLUMN $field SET DEFAULT $default");
|
|
|
|
break;
|
|
|
|
default:
|
|
switch (strtolower($type)) {
|
|
case "integer":
|
|
$type = "INTEGER";
|
|
break;
|
|
case "varchar":
|
|
$type = "VARCHAR";
|
|
break;
|
|
}
|
|
|
|
$default = "DEFAULT '$default'";
|
|
|
|
if (!empty($after)) {
|
|
$after = "AFTER $after";
|
|
}
|
|
|
|
if (!empty($oldfield)) {
|
|
execute_sql("ALTER TABLE {$CFG->prefix}$table RENAME COLUMN $oldfield $field");
|
|
} else {
|
|
execute_sql("ALTER TABLE {$CFG->prefix}$table ADD COLUMN $field $type");
|
|
}
|
|
|
|
execute_sql("ALTER TABLE {$CFG->prefix}$table ALTER COLUMN $field SET $null");
|
|
return execute_sql("ALTER TABLE {$CFG->prefix}$table ALTER COLUMN $field SET $default");
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/// GENERIC FUNCTIONS TO CHECK AND COUNT RECORDS ////////////////////////////////////////
|
|
|
|
/**
|
|
* Returns true or false depending on whether the specified record exists
|
|
*
|
|
* Returns true or false depending on whether the specified record exists
|
|
*
|
|
* @param type description
|
|
*/
|
|
function record_exists($table, $field1="", $value1="", $field2="", $value2="", $field3="", $value3="") {
|
|
|
|
global $CFG;
|
|
|
|
if ($field1) {
|
|
$select = "WHERE $field1 = '$value1'";
|
|
if ($field2) {
|
|
$select .= " AND $field2 = '$value2'";
|
|
if ($field3) {
|
|
$select .= " AND $field3 = '$value3'";
|
|
}
|
|
}
|
|
} else {
|
|
$select = "";
|
|
}
|
|
|
|
return record_exists_sql("SELECT * FROM $CFG->prefix$table $select LIMIT 1");
|
|
}
|
|
|
|
|
|
/**
|
|
* Returns true or false depending on whether the specified record exists
|
|
*
|
|
* The sql statement is provided as a string.
|
|
*
|
|
* @param type description
|
|
*/
|
|
function record_exists_sql($sql) {
|
|
|
|
global $db;
|
|
|
|
$rs = $db->Execute($sql);
|
|
if (empty($rs)) return false;
|
|
|
|
if ( $rs->RecordCount() ) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Get all the records and count them
|
|
*
|
|
* Get all the records and count them
|
|
*
|
|
* @param type description
|
|
*/
|
|
function count_records($table, $field1="", $value1="", $field2="", $value2="", $field3="", $value3="") {
|
|
|
|
global $CFG;
|
|
|
|
if ($field1) {
|
|
$select = "WHERE $field1 = '$value1'";
|
|
if ($field2) {
|
|
$select .= " AND $field2 = '$value2'";
|
|
if ($field3) {
|
|
$select .= " AND $field3 = '$value3'";
|
|
}
|
|
}
|
|
} else {
|
|
$select = "";
|
|
}
|
|
|
|
return count_records_sql("SELECT COUNT(*) FROM $CFG->prefix$table $select");
|
|
}
|
|
|
|
/**
|
|
* Get all the records and count them
|
|
*
|
|
* Get all the records and count them
|
|
*
|
|
* @param type description
|
|
*
|
|
*/
|
|
function count_records_select($table, $select="") {
|
|
|
|
global $CFG;
|
|
|
|
if ($select) {
|
|
$select = "WHERE $select";
|
|
}
|
|
|
|
return count_records_sql("SELECT COUNT(*) FROM $CFG->prefix$table $select");
|
|
}
|
|
|
|
|
|
/**
|
|
* Get all the records and count them
|
|
*
|
|
* The sql statement is provided as a string.
|
|
*
|
|
* @param type description
|
|
*/
|
|
function count_records_sql($sql) {
|
|
|
|
global $db;
|
|
|
|
$rs = $db->Execute("$sql");
|
|
if (empty($rs)) return 0;
|
|
|
|
return $rs->fields[0];
|
|
}
|
|
|
|
|
|
|
|
|
|
/// GENERIC FUNCTIONS TO GET, INSERT, OR UPDATE DATA ///////////////////////////////////
|
|
|
|
/**
|
|
* Get a single record as an object
|
|
*
|
|
* Get a single record as an object
|
|
*
|
|
* @param string $table the name of the table to select from
|
|
* @param string $field1 the name of the field for the first criteria
|
|
* @param string $value1 the value of the field for the first criteria
|
|
* @param string $field2 the name of the field for the second criteria
|
|
* @param string $value2 the value of the field for the second criteria
|
|
* @param string $field3 the name of the field for the third criteria
|
|
* @param string $value3 the value of the field for the third criteria
|
|
* @return object(fieldset) a fieldset object containing the first record selected
|
|
*/
|
|
function get_record($table, $field1, $value1, $field2="", $value2="", $field3="", $value3="") {
|
|
|
|
global $CFG;
|
|
|
|
$select = "WHERE $field1 = '$value1'";
|
|
|
|
if ($field2) {
|
|
$select .= " AND $field2 = '$value2'";
|
|
if ($field3) {
|
|
$select .= " AND $field3 = '$value3'";
|
|
}
|
|
}
|
|
|
|
return get_record_sql("SELECT * FROM $CFG->prefix$table $select");
|
|
}
|
|
|
|
/**
|
|
* Get a single record as an object
|
|
*
|
|
* The sql statement is provided as a string.
|
|
* A LIMIT is normally added to only look for 1 record
|
|
*
|
|
* @param type description
|
|
*/
|
|
function get_record_sql($sql) {
|
|
|
|
global $db, $CFG;
|
|
|
|
if ($CFG->debug > 7) { // Debugging mode - don't use limit
|
|
$limit = "";
|
|
} else {
|
|
$limit = " LIMIT 1"; // Workaround - limit to one record
|
|
}
|
|
|
|
if (!$rs = $db->Execute("$sql$limit")) {
|
|
if ($CFG->debug > 7) { // Debugging mode - print checks
|
|
$db->debug=true;
|
|
$db->Execute("$sql$limit");
|
|
$db->debug=false;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
if (!$recordcount = $rs->RecordCount()) {
|
|
return false; // Found no records
|
|
}
|
|
|
|
if ($recordcount == 1) { // Found one record
|
|
return (object)$rs->fields;
|
|
|
|
} else { // Error: found more than one record
|
|
notify("Error: Turn off debugging to hide this error.");
|
|
notify("$sql$limit");
|
|
if ($records = $rs->GetAssoc(true)) {
|
|
notify("Found more than one record in get_record_sql !");
|
|
print_object($records);
|
|
} else {
|
|
notify("Very strange error in get_record_sql !");
|
|
print_object($rs);
|
|
}
|
|
print_continue("$CFG->wwwroot/admin/config.php");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Gets one record from a table, as an object
|
|
*
|
|
* "select" is a fragment of SQL to define the selection criteria
|
|
*
|
|
* @param type description
|
|
*/
|
|
function get_record_select($table, $select="", $fields="*") {
|
|
|
|
global $CFG;
|
|
|
|
if ($select) {
|
|
$select = "WHERE $select";
|
|
}
|
|
|
|
return get_record_sql("SELECT $fields FROM $CFG->prefix$table $select");
|
|
}
|
|
|
|
|
|
/**
|
|
* Get a number of records as an array of objects
|
|
*
|
|
* Can optionally be sorted eg "time ASC" or "time DESC"
|
|
* If "fields" is specified, only those fields are returned
|
|
* The "key" is the first column returned, eg usually "id"
|
|
* limitfrom and limitnum must both be specified or not at all
|
|
*
|
|
* @param type description
|
|
*/
|
|
function get_records($table, $field="", $value="", $sort="", $fields="*", $limitfrom="", $limitnum="") {
|
|
|
|
global $CFG;
|
|
|
|
if ($field) {
|
|
$select = "WHERE $field = '$value'";
|
|
} else {
|
|
$select = "";
|
|
}
|
|
|
|
if ($limitfrom !== "") {
|
|
switch ($CFG->dbtype) {
|
|
case "mysql":
|
|
$limit = "LIMIT $limitfrom,$limitnum";
|
|
break;
|
|
case "postgres7":
|
|
$limit = "LIMIT $limitnum OFFSET $limitfrom";
|
|
break;
|
|
default:
|
|
$limit = "LIMIT $limitnum,$limitfrom";
|
|
}
|
|
} else {
|
|
$limit = "";
|
|
}
|
|
|
|
if ($sort) {
|
|
$sort = "ORDER BY $sort";
|
|
}
|
|
|
|
return get_records_sql("SELECT $fields FROM $CFG->prefix$table $select $sort $limit");
|
|
}
|
|
|
|
/**
|
|
* Get a number of records as an array of objects
|
|
*
|
|
* Can optionally be sorted eg "time ASC" or "time DESC"
|
|
* "select" is a fragment of SQL to define the selection criteria
|
|
* The "key" is the first column returned, eg usually "id"
|
|
*
|
|
* @param type description
|
|
*/
|
|
function get_records_select($table, $select="", $sort="", $fields="*") {
|
|
|
|
global $CFG;
|
|
|
|
if ($select) {
|
|
$select = "WHERE $select";
|
|
}
|
|
|
|
if ($sort) {
|
|
$sort = "ORDER BY $sort";
|
|
}
|
|
|
|
return get_records_sql("SELECT $fields FROM $CFG->prefix$table $select $sort");
|
|
}
|
|
|
|
|
|
/**
|
|
* Get a number of records as an array of objects
|
|
*
|
|
* Differs from get_records() in that the values variable
|
|
* can be a comma-separated list of values eg "4,5,6,10"
|
|
* Can optionally be sorted eg "time ASC" or "time DESC"
|
|
* The "key" is the first column returned, eg usually "id"
|
|
*
|
|
* @param type description
|
|
*/
|
|
function get_records_list($table, $field="", $values="", $sort="", $fields="*") {
|
|
|
|
global $CFG;
|
|
|
|
if ($field) {
|
|
$select = "WHERE $field in ($values)";
|
|
} else {
|
|
$select = "";
|
|
}
|
|
|
|
if ($sort) {
|
|
$sort = "ORDER BY $sort";
|
|
}
|
|
|
|
return get_records_sql("SELECT $fields FROM $CFG->prefix$table $select $sort");
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* Get a number of records as an array of objects
|
|
*
|
|
* The "key" is the first column returned, eg usually "id"
|
|
* The sql statement is provided as a string.
|
|
*
|
|
* @param type description
|
|
*/
|
|
function get_records_sql($sql) {
|
|
|
|
global $db;
|
|
|
|
$rs = $db->Execute("$sql");
|
|
if (empty($rs)) return false;
|
|
|
|
if ( $rs->RecordCount() > 0 ) {
|
|
if ($records = $rs->GetAssoc(true)) {
|
|
foreach ($records as $key => $record) {
|
|
$objects[$key] = (object) $record;
|
|
}
|
|
return $objects;
|
|
} else {
|
|
return false;
|
|
}
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get a number of records as an array of objects
|
|
*
|
|
* Can optionally be sorted eg "time ASC" or "time DESC"
|
|
* If "fields" is specified, only those fields are returned
|
|
* The "key" is the first column returned, eg usually "id"
|
|
*
|
|
* @param type description
|
|
*/
|
|
function get_records_menu($table, $field="", $value="", $sort="", $fields="*") {
|
|
|
|
global $CFG;
|
|
|
|
if ($field) {
|
|
$select = "WHERE $field = '$value'";
|
|
} else {
|
|
$select = "";
|
|
}
|
|
|
|
if ($sort) {
|
|
$sort = "ORDER BY $sort";
|
|
}
|
|
|
|
return get_records_sql_menu("SELECT $fields FROM $CFG->prefix$table $select $sort");
|
|
}
|
|
|
|
/**
|
|
* Get a number of records as an array of objects
|
|
*
|
|
* Can optionally be sorted eg "time ASC" or "time DESC"
|
|
* "select" is a fragment of SQL to define the selection criteria
|
|
* Returns associative array of first two fields
|
|
*
|
|
* @param type description
|
|
*/
|
|
function get_records_select_menu($table, $select="", $sort="", $fields="*") {
|
|
|
|
global $CFG;
|
|
|
|
if ($select) {
|
|
$select = "WHERE $select";
|
|
}
|
|
|
|
if ($sort) {
|
|
$sort = "ORDER BY $sort";
|
|
}
|
|
|
|
return get_records_sql_menu("SELECT $fields FROM $CFG->prefix$table $select $sort");
|
|
}
|
|
|
|
|
|
/**
|
|
* Given an SQL select, this function returns an associative
|
|
*
|
|
* array of the first two columns. This is most useful in
|
|
* combination with the choose_from_menu function to create
|
|
* a form menu.
|
|
*
|
|
* @param type description
|
|
*/
|
|
function get_records_sql_menu($sql) {
|
|
|
|
global $db;
|
|
|
|
$rs = $db->Execute("$sql");
|
|
if (empty($rs)) return false;
|
|
|
|
if ( $rs->RecordCount() > 0 ) {
|
|
while (!$rs->EOF) {
|
|
$menu[$rs->fields[0]] = $rs->fields[1];
|
|
$rs->MoveNext();
|
|
}
|
|
return $menu;
|
|
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get a single field from a database record
|
|
*
|
|
* longdesc
|
|
*
|
|
* @param type description
|
|
*/
|
|
function get_field($table, $return, $field1, $value1, $field2="", $value2="", $field3="", $value3="") {
|
|
|
|
global $db, $CFG;
|
|
|
|
$select = "WHERE $field1 = '$value1'";
|
|
|
|
if ($field2) {
|
|
$select .= " AND $field2 = '$value2'";
|
|
if ($field3) {
|
|
$select .= " AND $field3 = '$value3'";
|
|
}
|
|
}
|
|
|
|
$rs = $db->Execute("SELECT $return FROM $CFG->prefix$table $select");
|
|
if (empty($rs)) return false;
|
|
|
|
if ( $rs->RecordCount() == 1 ) {
|
|
return $rs->fields["$return"];
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set a single field in a database record
|
|
*
|
|
* longdesc
|
|
*
|
|
* @param type description
|
|
*/
|
|
function set_field($table, $newfield, $newvalue, $field1, $value1, $field2="", $value2="", $field3="", $value3="") {
|
|
|
|
global $db, $CFG;
|
|
|
|
$select = "WHERE $field1 = '$value1'";
|
|
|
|
if ($field2) {
|
|
$select .= " AND $field2 = '$value2'";
|
|
if ($field3) {
|
|
$select .= " AND $field3 = '$value3'";
|
|
}
|
|
}
|
|
|
|
return $db->Execute("UPDATE $CFG->prefix$table SET $newfield = '$newvalue' $select");
|
|
}
|
|
|
|
|
|
/**
|
|
* Delete one or more records from a table
|
|
*
|
|
* Delete one or more records from a table
|
|
*
|
|
* @param type description
|
|
*/
|
|
function delete_records($table, $field1="", $value1="", $field2="", $value2="", $field3="", $value3="") {
|
|
|
|
global $db, $CFG;
|
|
|
|
if ($field1) {
|
|
$select = "WHERE $field1 = '$value1'";
|
|
if ($field2) {
|
|
$select .= " AND $field2 = '$value2'";
|
|
if ($field3) {
|
|
$select .= " AND $field3 = '$value3'";
|
|
}
|
|
}
|
|
} else {
|
|
$select = "";
|
|
}
|
|
|
|
return $db->Execute("DELETE FROM $CFG->prefix$table $select");
|
|
}
|
|
|
|
/**
|
|
* Delete one or more records from a table
|
|
*
|
|
* "select" is a fragment of SQL to define the selection criteria
|
|
*
|
|
* @param type description
|
|
*/
|
|
function delete_records_select($table, $select="") {
|
|
|
|
global $CFG, $db;
|
|
|
|
if ($select) {
|
|
$select = "WHERE $select";
|
|
}
|
|
|
|
return $db->Execute("DELETE FROM $CFG->prefix$table $select");
|
|
}
|
|
|
|
|
|
/**
|
|
* Insert a record into a table and return the "id" field if required
|
|
*
|
|
* If the return ID isn't required, then this just reports success as true/false.
|
|
* $dataobject is an object containing needed data
|
|
*
|
|
* @param type description
|
|
*/
|
|
function insert_record($table, $dataobject, $returnid=true) {
|
|
|
|
global $db, $CFG;
|
|
|
|
// Get empty record from table
|
|
$infosql = "SELECT * FROM $CFG->prefix$table WHERE id ='-1'";
|
|
|
|
// Execute the query and get the empty recordset
|
|
$rs = $db->Execute($infosql);
|
|
|
|
// Convert data to array to hold the record data to insert
|
|
$record = (array)$dataobject;
|
|
|
|
//Get insertsql from adodb
|
|
$insertSQL = $db->GetInsertSQL($rs, $record);
|
|
|
|
if (! $rs = $db->Execute($insertSQL)) {
|
|
return false;
|
|
}
|
|
|
|
if (!$returnid) { // Return ID is not needed so just finish here.
|
|
return true;
|
|
}
|
|
|
|
switch ($CFG->dbtype) {
|
|
case "postgres7":
|
|
$oid = $db->Insert_ID();
|
|
if ($rs = $db->Execute("SELECT id FROM $CFG->prefix$table WHERE oid = $oid")) {
|
|
// every table needs to have a primary field named 'id' for this to work
|
|
if ($rs->RecordCount() == 1) {
|
|
return $rs->fields[0];
|
|
}
|
|
}
|
|
return false;
|
|
|
|
default:
|
|
return $db->Insert_ID(); // Should work on most databases, but not all!
|
|
}
|
|
}
|
|
|
|
|
|
function insert_record_old($table, $dataobject, $returnid=true) {
|
|
// Will be deleted soon if there are no problems with the new one
|
|
|
|
global $db, $CFG;
|
|
|
|
// Determine all the fields needed
|
|
if (! $columns = $db->MetaColumns("$CFG->prefix$table")) {
|
|
return false;
|
|
}
|
|
$data = (array)$dataobject;
|
|
|
|
// Pull out data from the dataobject that matches the fields in the table.
|
|
// If fields are missing or empty, then try to set the defaults explicitly
|
|
// because some databases (eg PostgreSQL) don't always set them properly
|
|
foreach ($columns as $column) {
|
|
if(isset($column->primary_key) and $column->primary_key == 1) {
|
|
$pkey = $column->name; // take column name of primary key
|
|
}
|
|
if ($column->name <> "id") {
|
|
if (isset($data[$column->name])) {
|
|
if ((string)$data[$column->name] == "" and !empty($column->has_default) and !empty($column->default_value)) {
|
|
$ddd[$column->name] = $column->default_value;
|
|
} else {
|
|
$ddd[$column->name] = $data[$column->name];
|
|
}
|
|
} else {
|
|
if (!empty($column->has_default) and !empty($column->default_value)) {
|
|
$ddd[$column->name] = $column->default_value;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Construct SQL queries
|
|
if (! $numddd = count($ddd)) {
|
|
return false;
|
|
}
|
|
|
|
$count = 0;
|
|
$inscolumns = "";
|
|
$insvalues = "";
|
|
$select = "";
|
|
|
|
foreach ($ddd as $key => $value) {
|
|
if (!is_null($value)){
|
|
if ($select) {
|
|
$inscolumns .= ", ";
|
|
$insvalues .= ", ";
|
|
$select .= " AND ";
|
|
}
|
|
$inscolumns .= "$key";
|
|
$insvalues .= "'$value'";
|
|
$select .= "$key = '$value'";
|
|
}
|
|
}
|
|
|
|
if (! $rs = $db->Execute("INSERT INTO $CFG->prefix$table ($inscolumns) VALUES ($insvalues)")) {
|
|
return false;
|
|
}
|
|
|
|
if ($returnid) {
|
|
if ($CFG->dbtype == "mysql" ) {
|
|
return $db->Insert_ID(); // ADOdb has stored the ID for us, but it isn't reliable
|
|
}
|
|
|
|
if ($CFG->dbtype == "postgres7" and isset($pkey)){
|
|
$oid = $db->Insert_ID();
|
|
if ($rs = $db->Execute("SELECT $pkey FROM $CFG->prefix$table WHERE oid = $oid")) {
|
|
if ($rs->RecordCount() == 1) {
|
|
return $rs->fields[0];
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
// Try to pull the record out again to find the id. This is the most cross-platform method.
|
|
if ($rs = $db->Execute("SELECT id FROM $CFG->prefix$table WHERE $select")) {
|
|
if ($rs->RecordCount() == 1) {
|
|
return $rs->fields[0];
|
|
}
|
|
}
|
|
|
|
return false;
|
|
|
|
} else {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Update a record in a table
|
|
*
|
|
* $dataobject is an object containing needed data
|
|
* Relies on $dataobject having a variable "id" to
|
|
* specify the record to update
|
|
*
|
|
* @param type description
|
|
*/
|
|
function update_record($table, $dataobject) {
|
|
|
|
global $db, $CFG;
|
|
|
|
if (! isset($dataobject->id) ) {
|
|
return false;
|
|
}
|
|
|
|
// Determine all the fields in the table
|
|
if (!$columns = $db->MetaColumns("$CFG->prefix$table")) {
|
|
return false;
|
|
}
|
|
$data = (array)$dataobject;
|
|
|
|
// Pull out data matching these fields
|
|
foreach ($columns as $column) {
|
|
if ($column->name <> "id" and isset($data[$column->name]) ) {
|
|
$ddd[$column->name] = $data[$column->name];
|
|
}
|
|
}
|
|
|
|
// Construct SQL queries
|
|
$numddd = count($ddd);
|
|
$count = 0;
|
|
$update = "";
|
|
|
|
foreach ($ddd as $key => $value) {
|
|
$count++;
|
|
$update .= "$key = '$value'";
|
|
if ($count < $numddd) {
|
|
$update .= ", ";
|
|
}
|
|
}
|
|
|
|
if ($rs = $db->Execute("UPDATE $CFG->prefix$table SET $update WHERE id = '$dataobject->id'")) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
/// USER DATABASE ////////////////////////////////////////////////
|
|
|
|
/**
|
|
* Get a complete user record, which includes all the info
|
|
*
|
|
* in the user record, as well as membership information
|
|
* Suitable for setting as $USER session cookie.
|
|
*
|
|
* @param type description
|
|
*/
|
|
function get_user_info_from_db($field, $value) {
|
|
|
|
if (!$field or !$value) {
|
|
return false;
|
|
}
|
|
|
|
if (! $user = get_record_select("user", "$field = '$value' AND deleted <> '1'")) {
|
|
return false;
|
|
}
|
|
|
|
// Add membership information
|
|
|
|
if ($site = get_site()) { // Everyone is always a member of the top course
|
|
$user->student[$site->id] = true;
|
|
}
|
|
|
|
if ($students = get_records("user_students", "userid", $user->id)) {
|
|
foreach ($students as $student) {
|
|
if (get_field("course", "visible", "id", $student->course)) {
|
|
$user->student[$student->course] = true;
|
|
$user->zoom[$student->course] = $student->zoom;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($teachers = get_records("user_teachers", "userid", $user->id)) {
|
|
foreach ($teachers as $teacher) {
|
|
$user->teacher[$teacher->course] = true;
|
|
if ($teacher->editall) {
|
|
$user->teacheredit[$teacher->course] = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($admins = get_records("user_admins", "userid", $user->id)) {
|
|
$user->admin = true;
|
|
}
|
|
|
|
if ($displays = get_records("course_display", "userid", $user->id)) {
|
|
foreach ($displays as $display) {
|
|
$user->display[$display->course] = $display->display;
|
|
}
|
|
}
|
|
|
|
if ($groups = get_records("groups_members", "userid", $user->id)) {
|
|
foreach ($groups as $groupmember) {
|
|
$courseid = get_field("groups", "courseid", "id", $groupmember->groupid);
|
|
$user->groupmember[$courseid] = $groupmember->groupid;
|
|
}
|
|
}
|
|
|
|
if ($preferences = get_records('user_preferences', 'userid', $user->id)) {
|
|
foreach ($preferences as $preference) {
|
|
$user->preference[$preference->name] = $preference->value;
|
|
}
|
|
}
|
|
|
|
return $user;
|
|
}
|
|
|
|
/**
|
|
* Updates user record to record their last access
|
|
*
|
|
* longdesc
|
|
*
|
|
*/
|
|
function update_user_in_db() {
|
|
|
|
global $db, $USER, $REMOTE_ADDR, $CFG;
|
|
|
|
if (!isset($USER->id))
|
|
return false;
|
|
|
|
$timenow = time();
|
|
if ($db->Execute("UPDATE {$CFG->prefix}user SET lastIP='$REMOTE_ADDR', lastaccess='$timenow'
|
|
WHERE id = '$USER->id' ")) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Does this username and password specify a valid admin user?
|
|
*
|
|
* longdesc
|
|
*
|
|
* @param type description
|
|
*/
|
|
function adminlogin($username, $md5password) {
|
|
|
|
global $CFG;
|
|
|
|
return record_exists_sql("SELECT u.id
|
|
FROM {$CFG->prefix}user u,
|
|
{$CFG->prefix}user_admins a
|
|
WHERE u.id = a.userid
|
|
AND u.username = '$username'
|
|
AND u.password = '$md5password'");
|
|
}
|
|
|
|
|
|
/**
|
|
* Get the guest user information from the database
|
|
*
|
|
* longdesc
|
|
*
|
|
* @param type description
|
|
*/
|
|
function get_guest() {
|
|
return get_user_info_from_db("username", "guest");
|
|
}
|
|
|
|
|
|
/**
|
|
* Returns $user object of the main admin user
|
|
*
|
|
* longdesc
|
|
*
|
|
* @param type description
|
|
*/
|
|
function get_admin () {
|
|
|
|
global $CFG;
|
|
|
|
if ( $admins = get_admins() ) {
|
|
foreach ($admins as $admin) {
|
|
return $admin; // ie the first one
|
|
}
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns list of all admins
|
|
*
|
|
* longdesc
|
|
*
|
|
* @param type description
|
|
*/
|
|
function get_admins() {
|
|
|
|
global $CFG;
|
|
|
|
return get_records_sql("SELECT u.*
|
|
FROM {$CFG->prefix}user u,
|
|
{$CFG->prefix}user_admins a
|
|
WHERE a.userid = u.id
|
|
ORDER BY u.id ASC");
|
|
}
|
|
|
|
/**
|
|
* Returns list of all creators
|
|
*
|
|
* longdesc
|
|
*
|
|
* @param type description
|
|
*/
|
|
function get_creators() {
|
|
|
|
global $CFG;
|
|
|
|
return get_records_sql("SELECT u.*
|
|
FROM {$CFG->prefix}user u,
|
|
{$CFG->prefix}user_coursecreators a
|
|
WHERE a.userid = u.id
|
|
ORDER BY u.id ASC");
|
|
}
|
|
|
|
/**
|
|
* Returns $user object of the main teacher for a course
|
|
*
|
|
* longdesc
|
|
*
|
|
* @param type description
|
|
*/
|
|
function get_teacher($courseid) {
|
|
|
|
global $CFG;
|
|
|
|
if ( $teachers = get_course_teachers($courseid, "t.authority ASC")) {
|
|
foreach ($teachers as $teacher) {
|
|
if ($teacher->authority) {
|
|
return $teacher; // the highest authority teacher
|
|
}
|
|
}
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Searches logs to find all enrolments since a certain date
|
|
*
|
|
* used to print recent activity
|
|
*
|
|
* @param type description
|
|
*/
|
|
function get_recent_enrolments($courseid, $timestart) {
|
|
|
|
global $CFG;
|
|
|
|
return get_records_sql("SELECT u.id, u.firstname, u.lastname
|
|
FROM {$CFG->prefix}user u,
|
|
{$CFG->prefix}user_students s,
|
|
{$CFG->prefix}log l
|
|
WHERE l.time > '$timestart'
|
|
AND l.course = '$courseid'
|
|
AND l.module = 'course'
|
|
AND l.action = 'enrol'
|
|
AND l.info = u.id
|
|
AND u.id = s.userid
|
|
AND s.course = '$courseid'
|
|
GROUP BY l.info
|
|
ORDER BY l.time ASC");
|
|
}
|
|
|
|
/**
|
|
* Returns list of all students in this course
|
|
*
|
|
* @param type description
|
|
*/
|
|
function get_course_students($courseid, $sort="s.timeaccess", $dir="", $page=0, $recordsperpage=99999,
|
|
$firstinitial="", $lastinitial="") {
|
|
|
|
global $CFG;
|
|
|
|
switch ($CFG->dbtype) {
|
|
case "mysql":
|
|
$limit = "LIMIT $page,$recordsperpage";
|
|
$LIKE = "LIKE";
|
|
break;
|
|
case "postgres7":
|
|
$limit = "LIMIT $recordsperpage OFFSET ".($page);
|
|
$LIKE = "ILIKE";
|
|
break;
|
|
default:
|
|
$limit = "LIMIT $recordsperpage,$page";
|
|
$LIKE = "ILIKE";
|
|
}
|
|
|
|
$select = "s.course = '$courseid' AND s.userid = u.id AND u.deleted = '0' ";
|
|
|
|
if ($firstinitial) {
|
|
$select .= " AND u.firstname $LIKE '$firstinitial%' ";
|
|
}
|
|
|
|
if ($lastinitial) {
|
|
$select .= " AND u.lastname $LIKE '$lastinitial%' ";
|
|
}
|
|
|
|
return get_records_sql("SELECT u.id, u.username, u.firstname, u.lastname, u.maildisplay, u.mailformat,
|
|
u.email, u.city, u.country, u.lastlogin, u.picture, u.lang, u.timezone, s.timeaccess as lastaccess
|
|
FROM {$CFG->prefix}user u,
|
|
{$CFG->prefix}user_students s
|
|
WHERE $select
|
|
ORDER BY $sort $dir $limit");
|
|
}
|
|
|
|
/**
|
|
* Counts the students in a given course, or a subset of them
|
|
*
|
|
* @param type description
|
|
*/
|
|
function count_course_students($course, $search="", $firstinitial="", $lastinitial="") {
|
|
|
|
global $CFG;
|
|
|
|
switch ($CFG->dbtype) {
|
|
case "mysql":
|
|
$LIKE = "LIKE";
|
|
break;
|
|
default:
|
|
$LIKE = "ILIKE";
|
|
}
|
|
|
|
$select = "s.course = '$course->id' AND s.userid = u.id AND u.deleted = '0'";
|
|
|
|
if ($search) {
|
|
$select .= " AND u.firstname $LIKE '%$search%' OR u.lastname $LIKE '%$search%'";
|
|
}
|
|
if ($firstinitial) {
|
|
$select .= " AND u.firstname $LIKE '$firstinitial%'";
|
|
}
|
|
if ($lastinitial) {
|
|
$select .= " AND u.lastname $LIKE '$lastinitial%'";
|
|
}
|
|
|
|
return count_records_sql("SELECT COUNT(*) FROM {$CFG->prefix}user u,{$CFG->prefix}user_students s WHERE $select");
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
* Returns list of all teachers in this course
|
|
*
|
|
* @param type description
|
|
*/
|
|
function get_course_teachers($courseid, $sort="t.authority ASC") {
|
|
|
|
global $CFG;
|
|
|
|
return get_records_sql("SELECT u.id, u.username, u.firstname, u.lastname, u.maildisplay, u.mailformat,
|
|
u.email, u.city, u.country, u.lastlogin, u.picture, u.lang, u.timezone,
|
|
t.authority,t.role,t.editall,t.timeaccess as lastaccess
|
|
FROM {$CFG->prefix}user u,
|
|
{$CFG->prefix}user_teachers t
|
|
WHERE t.course = '$courseid' AND t.userid = u.id AND u.deleted = '0'
|
|
ORDER BY $sort");
|
|
}
|
|
|
|
/**
|
|
* Returns all the users of a course: students and teachers
|
|
*
|
|
* If the "course" is actually the site, then return all site users.
|
|
*
|
|
* @param type description
|
|
*/
|
|
function get_course_users($courseid, $sort="timeaccess DESC") {
|
|
|
|
$site = get_site();
|
|
|
|
if ($courseid == $site->id) {
|
|
return get_site_users($sort);
|
|
}
|
|
|
|
/// Using this method because the single SQL just would not always work!
|
|
|
|
$teachers = get_course_teachers($courseid, $sort);
|
|
$students = get_course_students($courseid, $sort);
|
|
|
|
if ($teachers and $students) {
|
|
return array_merge($teachers, $students);
|
|
} else if ($teachers) {
|
|
return $teachers;
|
|
} else {
|
|
return $students;
|
|
}
|
|
|
|
/// Why wouldn't this work?
|
|
/// return get_records_sql("SELECT u.* FROM user u, user_students s, user_teachers t
|
|
/// WHERE (s.course = '$courseid' AND s.userid = u.id) OR
|
|
/// (t.course = '$courseid' AND t.userid = u.id)
|
|
/// ORDER BY $sort");
|
|
}
|
|
|
|
/**
|
|
* Returns a list of all active users who are enrolled
|
|
*
|
|
* or teaching in courses on this server
|
|
*
|
|
* @param type description
|
|
*/
|
|
function get_site_users($sort="u.lastaccess DESC", $select="") {
|
|
|
|
global $CFG, $db;
|
|
|
|
|
|
if ($select) {
|
|
$selectinfo = $select;
|
|
} else {
|
|
$selectinfo = "u.id, u.username, u.firstname, u.lastname, u.maildisplay, u.mailformat,".
|
|
"u.email, u.city, u.country, u.lastaccess, u.lastlogin, u.picture, u.lang, u.timezone";
|
|
}
|
|
|
|
|
|
if (!$students = get_records_sql("SELECT $selectinfo from {$CFG->prefix}user u, {$CFG->prefix}user_students s
|
|
WHERE s.userid = u.id GROUP BY u.id ORDER BY $sort")) {
|
|
$students = array();
|
|
}
|
|
if (!$teachers = get_records_sql("SELECT $selectinfo from {$CFG->prefix}user u, {$CFG->prefix}user_teachers t
|
|
WHERE t.userid = u.id GROUP BY u.id ORDER BY $sort")) {
|
|
$teachers = array();
|
|
}
|
|
if (!$admins = get_records_sql("SELECT $selectinfo from {$CFG->prefix}user u, {$CFG->prefix}user_admins a
|
|
WHERE a.userid = u.id GROUP BY u.id ORDER BY $sort")) {
|
|
$admins = array();
|
|
}
|
|
$users = array_merge($teachers, $students);
|
|
$users = array_merge($users, $admins);
|
|
return $users;
|
|
}
|
|
|
|
|
|
/**
|
|
* Returns a subset of users
|
|
*
|
|
* longdesc
|
|
*
|
|
* @param bookean $get if false then only a count of the records is returned
|
|
* @param string $search a simple string to search for
|
|
* @param boolean $confirmed a switch to allow/disallow unconfirmed users
|
|
* @param array(int) $exceptions a list of IDs to ignore, eg 2,4,5,8,9,10
|
|
* @param string $sort a SQL snippet for the sorting criteria to use
|
|
*/
|
|
function get_users($get=true, $search="", $confirmed=false, $exceptions="", $sort="firstname ASC") {
|
|
|
|
global $CFG;
|
|
|
|
switch ($CFG->dbtype) {
|
|
case "mysql":
|
|
$fullname = " CONCAT(firstname,\" \",lastname) ";
|
|
$LIKE = "LIKE";
|
|
break;
|
|
case "postgres7":
|
|
$fullname = " firstname||\" \"||lastname ";
|
|
$LIKE = "ILIKE";
|
|
break;
|
|
default:
|
|
$fullname = " firstname||\" \"||lastname ";
|
|
$LIKE = "ILIKE";
|
|
}
|
|
|
|
if ($search) {
|
|
$search = " AND ($fullname $LIKE '%$search%' OR email $LIKE '%$search%') ";
|
|
}
|
|
|
|
if ($confirmed) {
|
|
$confirmed = " AND confirmed = '1' ";
|
|
}
|
|
|
|
if ($exceptions) {
|
|
$exceptions = " AND id NOT IN ($exceptions) ";
|
|
}
|
|
|
|
if ($sort and $get) {
|
|
$sort = " ORDER BY $sort ";
|
|
} else {
|
|
$sort = "";
|
|
}
|
|
|
|
if ($get) {
|
|
return get_records_select("user", "username <> 'guest' AND deleted = 0 $search $confirmed $exceptions $sort");
|
|
} else {
|
|
return count_records_select("user", "username <> 'guest' AND deleted = 0 $search $confirmed $exceptions $sort");
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* shortdesc
|
|
*
|
|
* longdesc
|
|
*
|
|
* @param type description
|
|
*/
|
|
function get_users_listing($sort, $dir="ASC", $page=1, $recordsperpage=20, $search="") {
|
|
global $CFG;
|
|
|
|
switch ($CFG->dbtype) {
|
|
case "mysql":
|
|
$limit = "LIMIT $page,$recordsperpage";
|
|
$fullname = " CONCAT(firstname,\" \",lastname) ";
|
|
$LIKE = "LIKE";
|
|
break;
|
|
case "postgres7":
|
|
$limit = "LIMIT $recordsperpage OFFSET ".($page);
|
|
$fullname = " firstname||\" \"||lastname ";
|
|
$LIKE = "ILIKE";
|
|
break;
|
|
default:
|
|
$limit = "LIMIT $recordsperpage,$page";
|
|
$fullname = " firstname||\" \"||lastname ";
|
|
$LIKE = "LIKE";
|
|
}
|
|
|
|
if ($search) {
|
|
$search = " AND ($fullname $LIKE '%$search%' OR email $LIKE '%$search%') ";
|
|
}
|
|
|
|
return get_records_sql("SELECT id, username, email, firstname, lastname, city, country, lastaccess
|
|
FROM {$CFG->prefix}user
|
|
WHERE username <> 'guest'
|
|
AND deleted <> 1 and confirmed = 1 $search
|
|
ORDER BY $sort $dir $limit");
|
|
|
|
}
|
|
|
|
/**
|
|
* shortdesc
|
|
*
|
|
* longdesc
|
|
*
|
|
* @param type description
|
|
*/
|
|
function get_users_confirmed() {
|
|
global $CFG;
|
|
return get_records_sql("SELECT *
|
|
FROM {$CFG->prefix}user
|
|
WHERE confirmed = 1
|
|
AND deleted = 0
|
|
AND username <> 'guest'
|
|
AND username <> 'changeme'");
|
|
}
|
|
|
|
|
|
/**
|
|
* shortdesc
|
|
*
|
|
* longdesc
|
|
*
|
|
* @param type description
|
|
*/
|
|
function get_users_unconfirmed($cutofftime=2000000000) {
|
|
global $CFG;
|
|
return get_records_sql("SELECT *
|
|
FROM {$CFG->prefix}user
|
|
WHERE confirmed = 0
|
|
AND firstaccess > 0
|
|
AND firstaccess < '$cutofftime'");
|
|
}
|
|
|
|
|
|
/**
|
|
* shortdesc
|
|
*
|
|
* longdesc
|
|
*
|
|
* @param type description
|
|
*/
|
|
function get_users_longtimenosee($cutofftime) {
|
|
global $CFG;
|
|
return get_records_sql("SELECT DISTINCT *
|
|
FROM {$CFG->prefix}user_students
|
|
WHERE timeaccess > '0'
|
|
AND timeaccess < '$cutofftime' ");
|
|
}
|
|
|
|
/**
|
|
* Returns an array of group objects that the user is a member of
|
|
* in the given course. If userid isn't specified, then return a
|
|
* list of all groups in the course.
|
|
*
|
|
* @param type description
|
|
*/
|
|
function get_groups($courseid, $userid=0) {
|
|
global $CFG;
|
|
|
|
if ($userid) {
|
|
$dbselect = ", {$CFG->prefix}groups_members m";
|
|
$userselect = "AND m.groupid = g.id AND m.userid = '$userid'";
|
|
} else {
|
|
$dbselect = '';
|
|
$userselect = '';
|
|
}
|
|
|
|
return get_records_sql("SELECT DISTINCT g.*
|
|
FROM {$CFG->prefix}groups g $dbselect
|
|
WHERE g.courseid = '$courseid' $userselect ");
|
|
}
|
|
|
|
|
|
/**
|
|
* Returns an array of user objects
|
|
*
|
|
* @param type description
|
|
*/
|
|
function get_users_in_group($groupid, $sort="u.lastaccess DESC") {
|
|
global $CFG;
|
|
return get_records_sql("SELECT DISTINCT u.*
|
|
FROM {$CFG->prefix}user u,
|
|
{$CFG->prefix}groups_members m
|
|
WHERE m.groupid = '$groupid'
|
|
AND m.userid = u.id
|
|
ORDER BY $sort");
|
|
}
|
|
|
|
/**
|
|
* An efficient way of finding all the users who aren't in groups yet
|
|
*
|
|
* @param type description
|
|
*/
|
|
function get_users_not_in_group($courseid) {
|
|
global $CFG;
|
|
|
|
return array(); /// XXX TO BE DONE
|
|
}
|
|
|
|
/**
|
|
* Returns the user's group in a particular course
|
|
*
|
|
* @param type description
|
|
*/
|
|
function user_group($courseid, $userid) {
|
|
global $CFG;
|
|
|
|
return get_record_sql("SELECT g.*
|
|
FROM {$CFG->prefix}groups g,
|
|
{$CFG->prefix}groups_members m
|
|
WHERE g.courseid = '$courseid'
|
|
AND g.id = m.groupid
|
|
AND m.userid = '$userid'");
|
|
}
|
|
|
|
|
|
|
|
|
|
/// OTHER SITE AND COURSE FUNCTIONS /////////////////////////////////////////////
|
|
|
|
|
|
/**
|
|
* Returns $course object of the top-level site.
|
|
*
|
|
* Returns $course object of the top-level site.
|
|
*
|
|
* @param type description
|
|
*/
|
|
function get_site () {
|
|
|
|
if ( $course = get_record("course", "category", 0)) {
|
|
return $course;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Returns list of courses, for whole site, or category
|
|
*
|
|
* Returns list of courses, for whole site, or category
|
|
*
|
|
* @param type description
|
|
*/
|
|
function get_courses($categoryid="all", $sort="c.sortorder ASC", $fields="c.*") {
|
|
|
|
global $USER, $CFG;
|
|
|
|
$categoryselect = "";
|
|
if ($categoryid != "all") {
|
|
$categoryselect = "c.category = '$categoryid'";
|
|
}
|
|
|
|
$teachertable = "";
|
|
$visiblecourses = "";
|
|
if (!empty($USER)) { // May need to check they are a teacher
|
|
if (!iscreator()) {
|
|
$visiblecourses = "AND ((c.visible > 0) OR (t.userid = '$USER->id' AND t.course = c.id))";
|
|
$teachertable = ", {$CFG->prefix}user_teachers t";
|
|
}
|
|
} else {
|
|
$visiblecourses = "AND c.visible > 0";
|
|
}
|
|
|
|
if ($categoryselect or $visiblecourses) {
|
|
$selectsql = "{$CFG->prefix}course c $teachertable WHERE $categoryselect $visiblecourses";
|
|
} else {
|
|
$selectsql = "{$CFG->prefix}course c $teachertable";
|
|
}
|
|
|
|
|
|
return get_records_sql("SELECT DISTINCT $fields FROM $selectsql ORDER BY $sort");
|
|
}
|
|
|
|
|
|
/**
|
|
* Returns list of courses, for whole site, or category
|
|
*
|
|
* Similar to get_courses, but allows paging
|
|
*
|
|
* @param type description
|
|
*/
|
|
function get_courses_page($categoryid="all", $sort="c.sortorder ASC", $fields="c.*",
|
|
&$totalcount, $limitfrom="", $limitnum="") {
|
|
|
|
global $USER, $CFG;
|
|
|
|
$categoryselect = "";
|
|
if ($categoryid != "all") {
|
|
$categoryselect = "c.category = '$categoryid'";
|
|
}
|
|
|
|
$teachertable = "";
|
|
$visiblecourses = "";
|
|
if (!empty($USER)) { // May need to check they are a teacher
|
|
if (!iscreator()) {
|
|
$visiblecourses = "AND ((c.visible > 0) OR (t.userid = '$USER->id' AND t.course = c.id))";
|
|
$teachertable = ", {$CFG->prefix}user_teachers t";
|
|
}
|
|
} else {
|
|
$visiblecourses = "AND c.visible > 0";
|
|
}
|
|
|
|
if ($limitfrom !== "") {
|
|
switch ($CFG->dbtype) {
|
|
case "mysql":
|
|
$limit = "LIMIT $limitfrom,$limitnum";
|
|
break;
|
|
case "postgres7":
|
|
$limit = "LIMIT $limitnum OFFSET $limitfrom";
|
|
break;
|
|
default:
|
|
$limit = "LIMIT $limitnum,$limitfrom";
|
|
}
|
|
} else {
|
|
$limit = "";
|
|
}
|
|
|
|
$selectsql = "{$CFG->prefix}course c $teachertable WHERE $categoryselect $visiblecourses";
|
|
|
|
$totalcount = count_records_sql("SELECT COUNT(DISTINCT c.id) FROM $selectsql");
|
|
|
|
return get_records_sql("SELECT DISTINCT $fields FROM $selectsql ORDER BY $sort $limit");
|
|
}
|
|
|
|
|
|
/**
|
|
* shortdesc
|
|
*
|
|
* longdesc
|
|
*
|
|
* @param type description
|
|
*/
|
|
function get_my_courses($userid, $sort="visible DESC,fullname ASC") {
|
|
|
|
global $CFG;
|
|
|
|
$course = array();
|
|
|
|
if ($students = get_records("user_students", "userid", $userid, "", "id, course")) {
|
|
foreach ($students as $student) {
|
|
$course[$student->course] = $student->course;
|
|
}
|
|
}
|
|
if ($teachers = get_records("user_teachers", "userid", $userid, "", "id, course")) {
|
|
foreach ($teachers as $teacher) {
|
|
$course[$teacher->course] = $teacher->course;
|
|
}
|
|
}
|
|
if (empty($course)) {
|
|
return $course;
|
|
}
|
|
|
|
$courseids = implode(',', $course);
|
|
|
|
return get_records_list("course", "id", $courseids, $sort);
|
|
|
|
// The following is correct but VERY slow with large datasets
|
|
//
|
|
// return get_records_sql("SELECT c.*
|
|
// FROM {$CFG->prefix}course c,
|
|
// {$CFG->prefix}user_students s,
|
|
// {$CFG->prefix}user_teachers t
|
|
// WHERE (s.userid = '$userid' AND s.course = c.id)
|
|
// OR (t.userid = '$userid' AND t.course = c.id)
|
|
// GROUP BY c.id
|
|
// ORDER BY $sort");
|
|
}
|
|
|
|
|
|
/**
|
|
* Returns a list of courses that match a search
|
|
*
|
|
* Returns a list of courses that match a search
|
|
*
|
|
* @param type description
|
|
*/
|
|
function get_courses_search($searchterms, $sort="fullname ASC", $page=0, $recordsperpage=50, &$totalcount) {
|
|
|
|
global $CFG;
|
|
|
|
switch ($CFG->dbtype) {
|
|
case "mysql":
|
|
$limit = "LIMIT $page,$recordsperpage";
|
|
break;
|
|
case "postgres7":
|
|
$limit = "LIMIT $recordsperpage OFFSET ".($page * $recordsperpage);
|
|
break;
|
|
default:
|
|
$limit = "LIMIT $recordsperpage,$page";
|
|
}
|
|
|
|
//to allow case-insensitive search for postgesql
|
|
if ($CFG->dbtype == "postgres7") {
|
|
$LIKE = "ILIKE";
|
|
$NOTLIKE = "NOT ILIKE"; // case-insensitive
|
|
$REGEXP = "~*";
|
|
$NOTREGEXP = "!~*";
|
|
} else {
|
|
$LIKE = "LIKE";
|
|
$NOTLIKE = "NOT LIKE";
|
|
$REGEXP = "REGEXP";
|
|
$NOTREGEXP = "NOT REGEXP";
|
|
}
|
|
|
|
$fullnamesearch = "";
|
|
$summarysearch = "";
|
|
|
|
foreach ($searchterms as $searchterm) {
|
|
if ($fullnamesearch) {
|
|
$fullnamesearch .= " AND ";
|
|
}
|
|
if ($summarysearch) {
|
|
$summarysearch .= " AND ";
|
|
}
|
|
|
|
if (substr($searchterm,0,1) == "+") {
|
|
$searchterm = substr($searchterm,1);
|
|
$summarysearch .= " summary $REGEXP '(^|[^a-zA-Z0-9])$searchterm([^a-zA-Z0-9]|$)' ";
|
|
$fullnamesearch .= " fullname $REGEXP '(^|[^a-zA-Z0-9])$searchterm([^a-zA-Z0-9]|$)' ";
|
|
} else if (substr($searchterm,0,1) == "-") {
|
|
$searchterm = substr($searchterm,1);
|
|
$summarysearch .= " summary $NOTREGEXP '(^|[^a-zA-Z0-9])$searchterm([^a-zA-Z0-9]|$)' ";
|
|
$fullnamesearch .= " fullname $NOTREGEXP '(^|[^a-zA-Z0-9])$searchterm([^a-zA-Z0-9]|$)' ";
|
|
} else {
|
|
$summarysearch .= " summary $LIKE '%$searchterm%' ";
|
|
$fullnamesearch .= " fullname $LIKE '%$searchterm%' ";
|
|
}
|
|
|
|
}
|
|
|
|
$selectsql = "{$CFG->prefix}course WHERE ($fullnamesearch OR $summarysearch) AND category > '0'";
|
|
|
|
$totalcount = count_records_sql("SELECT COUNT(*) FROM $selectsql");
|
|
|
|
$courses = get_records_sql("SELECT * FROM $selectsql ORDER BY $sort $limit");
|
|
|
|
if ($courses) { /// Remove unavailable courses from the list
|
|
foreach ($courses as $key => $course) {
|
|
if (!$course->visible) {
|
|
if (!isteacher($course->id)) {
|
|
unset($courses[$key]);
|
|
$totalcount--;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return $courses;
|
|
}
|
|
|
|
|
|
/**
|
|
* Returns a sorted list of categories
|
|
*
|
|
* Returns a sorted list of categories
|
|
*
|
|
* @param type description
|
|
*/
|
|
function get_categories($parent="none", $sort="sortorder ASC") {
|
|
|
|
if ($parent == "none") {
|
|
$categories = get_records("course_categories", "", "", $sort);
|
|
} else {
|
|
$categories = get_records("course_categories", "parent", $parent, $sort);
|
|
}
|
|
if ($categories) { /// Remove unavailable categories from the list
|
|
$creator = iscreator();
|
|
foreach ($categories as $key => $category) {
|
|
if (!$category->visible) {
|
|
if (!$creator) {
|
|
unset($categories[$key]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return $categories;
|
|
}
|
|
|
|
|
|
/**
|
|
* reconcile $courseorder with a category object
|
|
*
|
|
* Given a category object, this function makes sure the courseorder
|
|
* variable reflects the real world.
|
|
*
|
|
* @param type description
|
|
*/
|
|
function fix_course_sortorder($categoryid, $sort="sortorder ASC") {
|
|
|
|
if (!$courses = get_records("course", "category", "$categoryid", "$sort", "id, sortorder")) {
|
|
set_field("course_categories", "coursecount", 0, "id", $categoryid);
|
|
return true;
|
|
}
|
|
|
|
$count = 0;
|
|
$modified = false;
|
|
|
|
foreach ($courses as $course) {
|
|
if ($course->sortorder != $count) {
|
|
set_field("course", "sortorder", $count, "id", $course->id);
|
|
$modified = true;
|
|
}
|
|
$count++;
|
|
}
|
|
|
|
if ($modified) {
|
|
set_field("course_categories", "timemodified", time(), "id", $categoryid);
|
|
}
|
|
set_field("course_categories", "coursecount", $count, "id", $categoryid);
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* This function creates a default separated/connected scale
|
|
*
|
|
* This function creates a default separated/connected scale
|
|
* so there's something in the database. The locations of
|
|
* strings and files is a bit odd, but this is because we
|
|
* need to maintain backward compatibility with many different
|
|
* existing language translations and older sites.
|
|
*
|
|
* @param type description
|
|
*/
|
|
function make_default_scale() {
|
|
|
|
global $CFG;
|
|
|
|
$defaultscale = NULL;
|
|
$defaultscale->courseid = 0;
|
|
$defaultscale->userid = 0;
|
|
$defaultscale->name = get_string("separateandconnected");
|
|
$defaultscale->scale = get_string("postrating1", "forum").",".
|
|
get_string("postrating2", "forum").",".
|
|
get_string("postrating3", "forum");
|
|
$defaultscale->timemodified = time();
|
|
|
|
/// Read in the big description from the file. Note this is not
|
|
/// HTML (despite the file extension) but Moodle format text.
|
|
$parentlang = get_string("parentlang");
|
|
if (is_readable("$CFG->dirroot/lang/$CFG->lang/help/forum/ratings.html")) {
|
|
$file = file("$CFG->dirroot/lang/$CFG->lang/help/forum/ratings.html");
|
|
} else if ($parentlang and is_readable("$CFG->dirroot/lang/$parentlang/help/forum/ratings.html")) {
|
|
$file = file("$CFG->dirroot/lang/$parentlang/help/forum/ratings.html");
|
|
} else if (is_readable("$CFG->dirroot/lang/en/help/forum/ratings.html")) {
|
|
$file = file("$CFG->dirroot/lang/en/help/forum/ratings.html");
|
|
} else {
|
|
$file = "";
|
|
}
|
|
|
|
$defaultscale->description = addslashes(implode("", $file));
|
|
|
|
if ($defaultscale->id = insert_record("scale", $defaultscale)) {
|
|
execute_sql("UPDATE {$CFG->prefix}forum SET scale = '$defaultscale->id'", false);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns a menu of all available scales from the site as well as the given course
|
|
*
|
|
* Returns a menu of all available scales from the site as well as the given course
|
|
*
|
|
* @param type description
|
|
*/
|
|
function get_scales_menu($courseid=0) {
|
|
|
|
global $CFG;
|
|
|
|
$sql = "SELECT id, name FROM {$CFG->prefix}scale
|
|
WHERE courseid = '0' or courseid = '$courseid'
|
|
ORDER BY courseid ASC, name ASC";
|
|
|
|
if ($scales = get_records_sql_menu("$sql")) {
|
|
return $scales;
|
|
}
|
|
|
|
make_default_scale();
|
|
|
|
return get_records_sql_menu("$sql");
|
|
}
|
|
|
|
/// MODULE FUNCTIONS /////////////////////////////////////////////////
|
|
|
|
/**
|
|
* Just gets a raw list of all modules in a course
|
|
*
|
|
* Just gets a raw list of all modules in a course
|
|
*
|
|
* @param type description
|
|
*/
|
|
function get_course_mods($courseid) {
|
|
global $CFG;
|
|
|
|
return get_records_sql("SELECT cm.*, m.name as modname
|
|
FROM {$CFG->prefix}modules m,
|
|
{$CFG->prefix}course_modules cm
|
|
WHERE cm.course = '$courseid'
|
|
AND cm.deleted = '0'
|
|
AND cm.module = m.id ");
|
|
}
|
|
|
|
/**
|
|
* Given an instance of a module, finds the coursemodule description
|
|
*
|
|
* Given an instance of a module, finds the coursemodule description
|
|
*
|
|
* @param type description
|
|
*/
|
|
function get_coursemodule_from_instance($modulename, $instance, $courseid) {
|
|
|
|
global $CFG;
|
|
|
|
return get_record_sql("SELECT cm.*, m.name
|
|
FROM {$CFG->prefix}course_modules cm,
|
|
{$CFG->prefix}modules md,
|
|
{$CFG->prefix}$modulename m
|
|
WHERE cm.course = '$courseid' AND
|
|
cm.deleted = '0' AND
|
|
cm.instance = m.id AND
|
|
md.name = '$modulename' AND
|
|
md.id = cm.module AND
|
|
m.id = '$instance'");
|
|
|
|
}
|
|
|
|
/**
|
|
* Returns an array of all the active instances of a particular module in a given course, sorted in the order they are defined
|
|
*
|
|
* Returns an array of all the active instances of a particular
|
|
* module in a given course, sorted in the order they are defined
|
|
* in the course. Returns false on any errors.
|
|
*
|
|
* @param string $modulename the name of the module to get instances for
|
|
* @param object(course) $course this depends on an accurate $course->modinfo
|
|
*/
|
|
function get_all_instances_in_course($modulename, $course) {
|
|
|
|
global $CFG;
|
|
|
|
if (!$modinfo = unserialize($course->modinfo)) {
|
|
return array();
|
|
}
|
|
|
|
if (!$rawmods = get_records_sql("SELECT cm.id as coursemodule, m.*,cw.section,cm.visible as visible,cm.groupmode
|
|
FROM {$CFG->prefix}course_modules cm,
|
|
{$CFG->prefix}course_sections cw,
|
|
{$CFG->prefix}modules md,
|
|
{$CFG->prefix}$modulename m
|
|
WHERE cm.course = '$course->id' AND
|
|
cm.instance = m.id AND
|
|
cm.deleted = '0' AND
|
|
cm.section = cw.id AND
|
|
md.name = '$modulename' AND
|
|
md.id = cm.module")) {
|
|
return array();
|
|
}
|
|
|
|
// Hide non-visible instances from students
|
|
if (isteacher($course->id)) {
|
|
$invisible = -1;
|
|
} else {
|
|
$invisible = 0;
|
|
}
|
|
|
|
foreach ($modinfo as $mod) {
|
|
if ($mod->mod == $modulename and $mod->visible > $invisible) {
|
|
$instance = $rawmods[$mod->cm];
|
|
if (!empty($mod->extra)) {
|
|
$instance->extra = $mod->extra;
|
|
}
|
|
$outputarray[] = $instance;
|
|
}
|
|
}
|
|
|
|
return $outputarray;
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
* determine whether a module instance is visible within a course
|
|
*
|
|
* Given a valid module object with info about the id and course,
|
|
* and the module's type (eg "forum") returns whether the object
|
|
* is visible or not
|
|
*
|
|
* @param type description
|
|
*/
|
|
function instance_is_visible($moduletype, $module) {
|
|
|
|
global $CFG;
|
|
|
|
if ($records = get_records_sql("SELECT cm.instance, cm.visible
|
|
FROM {$CFG->prefix}course_modules cm,
|
|
{$CFG->prefix}modules m
|
|
WHERE cm.course = '$module->course' AND
|
|
cm.module = m.id AND
|
|
m.name = '$moduletype' AND
|
|
cm.instance = '$module->id'")) {
|
|
|
|
foreach ($records as $record) { // there should only be one - use the first one
|
|
return $record->visible;
|
|
}
|
|
}
|
|
|
|
return true; // visible by default!
|
|
}
|
|
|
|
|
|
|
|
|
|
/// LOG FUNCTIONS /////////////////////////////////////////////////////
|
|
|
|
|
|
/**
|
|
* Add an entry to the log table.
|
|
*
|
|
* Add an entry to the log table. These are "action" focussed rather
|
|
* than web server hits, and provide a way to easily reconstruct what
|
|
* any particular student has been doing.
|
|
*
|
|
* @param int $course the course id
|
|
* @param string $module the module name - e.g. forum, journal, resource, course, user etc
|
|
* @param string $action view, edit, post (often but not always the same as the file.php)
|
|
* @param string $url the file and parameters used to see the results of the action
|
|
* @param string $info additional description information
|
|
*/
|
|
function add_to_log($courseid, $module, $action, $url="", $info="") {
|
|
|
|
global $db, $CFG, $USER, $REMOTE_ADDR;
|
|
|
|
if (isset($USER->realuser)) { // Don't log
|
|
return;
|
|
}
|
|
|
|
$userid = empty($USER->id) ? "" : $USER->id;
|
|
|
|
$timenow = time();
|
|
$info = addslashes($info);
|
|
|
|
$result = $db->Execute("INSERT INTO {$CFG->prefix}log (time,
|
|
userid,
|
|
course,
|
|
ip,
|
|
module,
|
|
action,
|
|
url,
|
|
info)
|
|
VALUES ('$timenow',
|
|
'$userid',
|
|
'$courseid',
|
|
'$REMOTE_ADDR',
|
|
'$module',
|
|
'$action',
|
|
'$url',
|
|
'$info')");
|
|
|
|
if (!$result and ($CFG->debug > 7)) {
|
|
echo "<P>Error: Could not insert a new entry to the Moodle log</P>"; // Don't throw an error
|
|
}
|
|
|
|
if (isstudent($courseid)) {
|
|
$db->Execute("UPDATE {$CFG->prefix}user_students SET timeaccess = '$timenow' ".
|
|
"WHERE course = '$courseid' AND userid = '$userid'");
|
|
}
|
|
|
|
if (isteacher($courseid, false, false)) {
|
|
$db->Execute("UPDATE {$CFG->prefix}user_teachers SET timeaccess = '$timenow' ".
|
|
"WHERE course = '$courseid' AND userid = '$userid'");
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* select all log records based on SQL criteria
|
|
*
|
|
* select all log records based on SQL criteria
|
|
*
|
|
* @param string $select SQL select criteria
|
|
* @param string $order SQL order by clause to sort the records returned
|
|
*/
|
|
function get_logs($select, $order="l.time DESC", $limitfrom="", $limitnum="", &$totalcount) {
|
|
global $CFG;
|
|
|
|
if ($limitfrom !== "") {
|
|
switch ($CFG->dbtype) {
|
|
case "mysql":
|
|
$limit = "LIMIT $limitfrom,$limitnum";
|
|
break;
|
|
case "postgres7":
|
|
$limit = "LIMIT $limitnum OFFSET $limitfrom";
|
|
break;
|
|
default:
|
|
$limit = "LIMIT $limitnum,$limitfrom";
|
|
}
|
|
} else {
|
|
$limit = "";
|
|
}
|
|
|
|
if ($order) {
|
|
$order = "ORDER BY $order";
|
|
}
|
|
|
|
$selectsql = "{$CFG->prefix}log l, {$CFG->prefix}user u WHERE $select";
|
|
|
|
$totalcount = count_records_sql("SELECT COUNT(*) FROM $selectsql");
|
|
|
|
return get_records_sql("SELECT l.*, u.firstname, u.lastname, u.picture
|
|
FROM $selectsql $order $limit");
|
|
}
|
|
|
|
|
|
/**
|
|
* select all log records for a given course and user
|
|
*
|
|
* select all log records for a given course and user
|
|
*
|
|
* @param type description
|
|
*/
|
|
function get_logs_usercourse($userid, $courseid, $coursestart) {
|
|
global $CFG;
|
|
|
|
if ($courseid) {
|
|
$courseselect = " AND course = '$courseid' ";
|
|
}
|
|
|
|
return get_records_sql("SELECT floor((`time` - $coursestart)/86400) as day, count(*) as num
|
|
FROM {$CFG->prefix}log
|
|
WHERE userid = '$userid'
|
|
AND `time` > '$coursestart' $courseselect
|
|
GROUP BY day ");
|
|
}
|
|
|
|
/**
|
|
* select all log records for a given course, user, and day
|
|
*
|
|
* select all log records for a given course, user, and day
|
|
*
|
|
* @param type description
|
|
*/
|
|
function get_logs_userday($userid, $courseid, $daystart) {
|
|
global $CFG;
|
|
|
|
if ($courseid) {
|
|
$courseselect = " AND course = '$courseid' ";
|
|
}
|
|
|
|
return get_records_sql("SELECT floor((`time` - $daystart)/3600) as hour, count(*) as num
|
|
FROM {$CFG->prefix}log
|
|
WHERE userid = '$userid'
|
|
AND `time` > '$daystart' $courseselect
|
|
GROUP BY hour ");
|
|
}
|
|
|
|
/// GENERAL HELPFUL THINGS ///////////////////////////////////
|
|
|
|
/**
|
|
* dump a given object's information in a PRE block
|
|
*
|
|
* dump a given object's information in a PRE block
|
|
* Mostly just for debugging
|
|
*
|
|
* @param type description
|
|
*/
|
|
function print_object($object) {
|
|
|
|
echo "<PRE>";
|
|
print_r($object);
|
|
echo "</PRE>";
|
|
}
|
|
|
|
|
|
|
|
// vim:autoindent:expandtab:shiftwidth=4:tabstop=4:tw=140:
|
|
?>
|