def cell(cell, header, ts, i): """ Format a table cell. Adds a class attribute to all cells in the currently active column. @param cell The cell to format. @param header An array of column headers in the format described in theme_table(). @param ts The current table sort context as returned from hook_init(). @param i The index of the cell's table column. @return A properly formatted cell, ready for _theme_table_cell(). """ if (php.isset(header[i]['data']) and header[i]['data'] == ts['name'] and not php.empty(header[i]['field'])): if php.is_array(cell): if php.isset(cell['class']): cell['class'] += ' active' else: cell['class'] = 'active' else: cell = {'data': cell, 'class': 'active'} return cell
def connect(url): """ Initialise a database connection. Note that mysqli does not support persistent connections. """ # Check if MySQLi support is present in PHP url = php.parse_url(url, 3306) # Decode url-encoded information in the db connection string url['user'] = php.urldecode(url['user']) # Test if database url has a password. url['pass'] = (php.urldecode(url['pass']) if php.isset(url, 'pass') else '') url['host'] = php.urldecode(url['host']) url['path'] = php.urldecode(url['path']) if (not php.isset(url, 'port')): url['port'] = None connection = DrupyMySQL.mysqli_real_connect(\ url['host'], url['user'], url['pass'], php.substr(url['path'], 1), \ url['port'], '', DrupyMySQL.MYSQLI_CLIENT_FOUND_ROWS) if (DrupyMySQL.mysqli_connect_errno() > 0): _db_error_page(DrupyMySQL.mysqli_connect_error()) # Force UTF-8. DrupyMySQL.mysqli_query(connection, 'SET NAMES "utf8"') # Require ANSI mode to improve SQL portability. DrupyMySQL.mysqli_query(connection, "SET php.SESSION sql_mode='ANSI'") return connection
def _create_field_sql(name, spec): """ Create an SQL string for a field to be used in table creation or alteration. Before passing a field out of a schema definition into this function it has to be processed by _db_process_field(). @param name Name of the field. @param spec The field specification, as per the schema data structure format. """ sql = "`" + name + "` " . spec['mysql_type'] if (php.isset(spec, 'length')): sql += '(' + spec['length'] + ')' elif (php.isset(spec, 'precision') and php.isset(spec, 'scale')): sql += '(' + spec['precision'] + ', ' + spec['scale'] + ')' if (not php.empty(spec['unsigned'])): sql += ' unsigned' if (not php.empty(spec['not None'])): sql += ' NOT None' if (not php.empty(spec['auto_increment'])): sql += ' auto_increment' if (php.isset(spec, 'default')): if (is_string(spec['default'])): spec['default'] = "'" + spec['default'] + "'" sql += ' DEFAULT ' + spec['default'] if (php.empty(spec['not None']) and not php.isset(spec, 'default')): sql += ' DEFAULT None' return sql
def drupal_load(type_, name): """ Includes a file with the provided type and name. This prevents including a theme, engine, plugin, etc., more than once. @param type The type of item to load (i.e. theme, theme_engine, plugin). @param name The name of the item to load. @return TRUE if the item is loaded or has already been loaded. """ php.static(drupal_load, 'files', {}) if (not php.isset(drupal_load.files, type)): drupal_load.files[type_] = {} if (php.isset(drupal_load.files[type_], name)): return True else: filename = drupal_get_filename(type_, name) if (filename != False): lib_plugin.plugins[name] = DrupyImport.import_file(filename) drupal_load.files[type_][name] = True return True else: return False
def drupal_load(type_, name): """ Includes a file with the provided type and name. This prevents including a theme, engine, plugin, etc., more than once. @param type The type of item to load (i.e. theme, theme_engine, plugin). @param name The name of the item to load. @return TRUE if the item is loaded or has already been loaded. """ php.static(drupal_load, "files", {}) if not php.isset(drupal_load.files, type): drupal_load.files[type_] = {} if php.isset(drupal_load.files[type_], name): return True else: filename = drupal_get_filename(type_, name) if filename != False: lib_plugin.plugins[name] = DrupyImport.import_file(filename) drupal_load.files[type_][name] = True return True else: return False
def drupal_set_message(message=None, type="status", repeat=True): """ Set a message which reflects the status of the performed operation. If the def is called with no arguments, this def returns all set messages without clearing them. @param message The message should begin with a capital letter and always ends with a period '.'. @param type The type of the message. One of the following values are possible: - 'status' - 'warning' - 'error' @param repeat If this is FALSE and the message is already set, then the message won't be repeated. """ if message: if not php.isset(php.SESSION, "messages"): php.SESSION["messages"] = {} if not php.isset(php.SESSION["messages"], type): php.SESSION["messages"][type] = [] if repeat or not php.in_array(message, php.SESSION["messages"][type]): php.SESSION["messages"][type].append(message) # messages not set when DB connection fails return php.SESSION["messages"] if php.isset(php.SESSION, "messages") else None
def _create_field_sql(name, spec): """ Create an SQL string for a field to be used in table creation or alteration. Before passing a field out of a schema definition into this function it has to be processed by _db_process_field(). @param name Name of the field. @param spec The field specification, as per the schema data structure format. """ sql = "`" + name + "` ".spec['mysql_type'] if (php.isset(spec, 'length')): sql += '(' + spec['length'] + ')' elif (php.isset(spec, 'precision') and php.isset(spec, 'scale')): sql += '(' + spec['precision'] + ', ' + spec['scale'] + ')' if (not php.empty(spec['unsigned'])): sql += ' unsigned' if (not php.empty(spec['not None'])): sql += ' NOT None' if (not php.empty(spec['auto_increment'])): sql += ' auto_increment' if (php.isset(spec, 'default')): if (is_string(spec['default'])): spec['default'] = "'" + spec['default'] + "'" sql += ' DEFAULT ' + spec['default'] if (php.empty(spec['not None']) and not php.isset(spec, 'default')): sql += ' DEFAULT None' return sql
def arg(index = None, path = None): """ Return a component of the current Drupal path. When viewing a page at the path "admin/build/types", for example, arg(0) would return "admin", arg(1) would return "content", and arg(2) would return "types". Avoid use of this function where possible, as resulting code is hard to read. Instead, attempt to use named arguments in menu callback functions. See the explanation in menu.inc for how to construct callbacks that take arguments. @param index The index of the component, where each component is separated by a '/' (forward-slash), and where the first component has an index of 0 (zero). @return The component specified by index, or NULL if the specified component was not found. """ php.static(arg, 'arguments', {}) if (path is None): path = php.GET['q']; if (not php.isset(arg.arguments, path)): arg.arguments[path] = php.explode('/', path); if (index is None): return arg.arguments[path]; if (php.isset(arg.arguments[path], index)): return arg.arguments[path][index];
def drupal_set_message(message=None, type='status', repeat=True): """ Set a message which reflects the status of the performed operation. If the def is called with no arguments, this def returns all set messages without clearing them. @param message The message should begin with a capital letter and always ends with a period '.'. @param type The type of the message. One of the following values are possible: - 'status' - 'warning' - 'error' @param repeat If this is FALSE and the message is already set, then the message won't be repeated. """ if (message): if (not php.isset(php.SESSION, 'messages')): php.SESSION['messages'] = {} if (not php.isset(php.SESSION['messages'], type)): php.SESSION['messages'][type] = [] if (repeat or not php.in_array(message, php.SESSION['messages'][type])): php.SESSION['messages'][type].append(message) # messages not set when DB connection fails return (php.SESSION['messages'] if php.isset(php.SESSION, 'messages') else \ None)
def arg(index=None, path=None): """ Return a component of the current Drupal path. When viewing a page at the path "admin/build/types", for example, arg(0) would return "admin", arg(1) would return "content", and arg(2) would return "types". Avoid use of this function where possible, as resulting code is hard to read. Instead, attempt to use named arguments in menu callback functions. See the explanation in menu.inc for how to construct callbacks that take arguments. @param index The index of the component, where each component is separated by a '/' (forward-slash), and where the first component has an index of 0 (zero). @return The component specified by index, or NULL if the specified component was not found. """ php.static(arg, 'arguments', {}) if (path is None): path = php.GET['q'] if (not php.isset(arg.arguments, path)): arg.arguments[path] = php.explode('/', path) if (index is None): return arg.arguments[path] if (php.isset(arg.arguments[path], index)): return arg.arguments[path][index]
def theme_preprocess_page(vars_): """ Override or insert variables into the page template. """ php.Reference.check(vars_) vars_['tabs2'] = menu_secondary_local_tasks() vars_['primary_nav'] = (lib_theme.theme('links', \ vars_['main_menu'], {'class' : 'links main-menu'}) if \ php.isset(vars_, 'main_menu') else False) vars_['secondary_nav'] = (lib_theme.theme('links', \ vars_['secondary_menu'], \ {'class' : 'links secondary-menu'}) if \ php.isset(vars_, 'secondary_menu') else False) vars_['ie_styles'] = get_ie_styles() # Prepare header site_fields = [] if (not php.empty(vars_['site_name'])): site_fields.append( check_plain(vars_['site_name']) ) if (not php.empty(vars_['site_slogan'])): site_fields.append( check_plain(vars_['site_slogan']) ) vars_['site_title'] = php.implode(' ', site_fields) if (not php.empty(site_fields)): site_fields[0] = '<span>' + site_fields[0] + '</span>' vars_['site_html'] = php.implode(' ', site_fields) # Hook into color.module if (lib_plugin.exists('color')): lib_plugin.plugins['color']._page_alter(vars_)
def rebuild_cache(): """ Rebuild the database cache of plugin files. @return The array of filesystem objects used to rebuild the cache. """ # Get current list of plugins files = drupal_system_listing('\.plugin$', 'plugins', 'name', 0) # Extract current files from database. system_get_files_database(files, 'plugin') ksort(files) # Set defaults for plugin info defaults = { 'dependencies' : [], 'dependents' : [], 'description' : '', 'version' : None, 'php' : DRUPAL_MINIMUM_PHP, } for filename,file in files.items(): # Look for the info file. file.info = drupal_parse_info_file(php.dirname(file.filename) + '/' + \ file.name + '.info') # Skip plugins that don't provide info. if (php.empty(file.info)): del(files[filename]) continue # Merge in defaults and save. files[filename].info = file.info + defaults # Invoke hook_system_info_alter() to give installed plugins a chance to # modify the data in the .info files if necessary. drupal_alter('system_info', files[filename].info, files[filename]) # Log the critical hooks implemented by this plugin. bootstrap = 0 for hook in bootstrap_hooks(): if (plugin_hook(file.name, hook)): bootstrap = 1 break # Update the contents of the system table: if (php.isset(file, 'status') or (php.isset(file, 'old_filename') and \ file.old_filename != file.filename)): db_query(\ "UPDATE {system} SET info = '%s', name = '%s', " + \ "filename = '%s', bootstrap = %d WHERE filename = '%s'", \ php.serialize(files[filename].info), file.name, \ file.filename, bootstrap, file.old_filename) else: # This is a new plugin. files[filename].status = 0 db_query(\ "INSERT INTO {system} (name, info, type, " + \ "filename, status, bootstrap) VALUES " + \ "('%s', '%s', '%s', '%s', %d, %d)", \ file.name, php.serialize(files[filename].info), \ 'plugin', file.filename, 0, bootstrap) files = _plugin_build_dependencies(files) return files
def rebuild_cache(): """ Rebuild the database cache of plugin files. @return The array of filesystem objects used to rebuild the cache. """ # Get current list of plugins files = drupal_system_listing('\.plugin$', 'plugins', 'name', 0) # Extract current files from database. system_get_files_database(files, 'plugin') ksort(files) # Set defaults for plugin info defaults = { 'dependencies': [], 'dependents': [], 'description': '', 'version': None, 'php': DRUPAL_MINIMUM_PHP, } for filename, file in files.items(): # Look for the info file. file.info = drupal_parse_info_file(php.dirname(file.filename) + '/' + \ file.name + '.info') # Skip plugins that don't provide info. if (php.empty(file.info)): del (files[filename]) continue # Merge in defaults and save. files[filename].info = file.info + defaults # Invoke hook_system_info_alter() to give installed plugins a chance to # modify the data in the .info files if necessary. drupal_alter('system_info', files[filename].info, files[filename]) # Log the critical hooks implemented by this plugin. bootstrap = 0 for hook in bootstrap_hooks(): if (plugin_hook(file.name, hook)): bootstrap = 1 break # Update the contents of the system table: if (php.isset(file, 'status') or (php.isset(file, 'old_filename') and \ file.old_filename != file.filename)): db_query(\ "UPDATE {system} SET info = '%s', name = '%s', " + \ "filename = '%s', bootstrap = %d WHERE filename = '%s'", \ php.serialize(files[filename].info), file.name, \ file.filename, bootstrap, file.old_filename) else: # This is a new plugin. files[filename].status = 0 db_query(\ "INSERT INTO {system} (name, info, type, " + \ "filename, status, bootstrap) VALUES " + \ "('%s', '%s', '%s', '%s', %d, %d)", \ file.name, php.serialize(files[filename].info), \ 'plugin', file.filename, 0, bootstrap) files = _plugin_build_dependencies(files) return files
def drupal_initialize_variables(): """ Initialize variables needed for the rest of the execution. """ if (not php.isset(php.SERVER, 'HTTP_REFERER')): php.SERVER['HTTP_REFERER'] = '' if (not php.isset(php.SERVER, 'SERVER_PROTOCOL') or \ (php.SERVER['SERVER_PROTOCOL'] != 'HTTP/1.0' and \ php.SERVER['SERVER_PROTOCOL'] != 'HTTP/1.1')): php.SERVER['SERVER_PROTOCOL'] = 'HTTP/1.0'
def drupal_initialize_variables(): """ Initialize variables needed for the rest of the execution. """ if not php.isset(php.SERVER, "HTTP_REFERER"): php.SERVER["HTTP_REFERER"] = "" if not php.isset(php.SERVER, "SERVER_PROTOCOL") or ( php.SERVER["SERVER_PROTOCOL"] != "HTTP/1.0" and php.SERVER["SERVER_PROTOCOL"] != "HTTP/1.1" ): php.SERVER["SERVER_PROTOCOL"] = "HTTP/1.0"
def install_page(content): """ Generate a themed installation page. Note: this function is not themeable. @param content The page content to show. """ drupal_set_header('Content-Type: text/html; charset=utf-8') # Assign content. variables['content'] = content # Delay setting the message variable so it can be processed below. variables['show_messages'] = False # The maintenance preprocess function is recycled here. template_preprocess_maintenance_page(variables) # Special handling of error messages messages = drupal_set_message() if (php.isset(messages, 'error')): title = (st('The following errors must be resolved before you can ' + \ 'continue the installation process') if \ (php.count(messages['error']) > 1) else \ st('The following error must be resolved before you can ' + \ 'continue the installation process')) variables['messages'] += '<h3>' + title + ':</h3>' variables['messages'] += theme('status_messages', 'error') variables['content'] += '<p>' + st('Please check the error ' + \ 'messages and <a href="not url">try again</a>.', \ {'not url' : request_uri()}) + '</p>' # Special handling of warning messages if (php.isset(messages, 'warning')): title = (st('The following installation warnings should be ' + \ 'carefully reviewed') if \ (php.count(messages['warning']) > 1) else \ st('The following installation warning should be carefully reviewed')) variables['messages'] += '<h4>' + title + ':</h4>' variables['messages'] += theme('status_messages', 'warning') # Special handling of status messages if (php.isset(messages, 'status')): title = (st('The following installation warnings should be ' + \ 'carefully reviewed, but in most cases may be safely ignored') if \ (php.count(messages['status']) > 1) else st('The following ' + \ 'installation warning should be carefully reviewed, but in ' + \ 'most cases may be safely ignored')) variables['messages'] += '<h4>' + title + ':</h4>' variables['messages'] += theme('status_messages', 'status') # This was called as a theme hook (not template), so we need to # fix path_to_theme() for the template, to point at the actual # theme rather than system plugin as owner of the hook. lib_appglobals.theme_path = 'themes/garland' return theme_render_template('themes/garland/maintenance-page.tpl.py', \ variables)
def drupal_page_cache_header(cache): """ Set HTTP headers in preparation for a cached page response. The general approach here is that anonymous users can keep a local cache of the page, but must revalidate it on every request. Then, they are given a '304 Not Modified' response as long as they stay logged out and the page has not been modified. """ # Set default values: last_modified = php.gmdate("D, d M Y H:i:s", cache.created) + " GMT" etag = '"' + drupy_md5(last_modified) + '"' # See if the client has provided the required HTTP headers: if_modified_since = ( php.stripslashes(php.SERVER["HTTP_IF_MODIFIED_SINCE"]) if php.isset(php.SERVER, "HTTP_IF_MODIFIED_SINCE") else False ) if_none_match = ( php.stripslashes(php.SERVER["HTTP_IF_NONE_MATCH"]) if php.isset(php.SERVER, "HTTP_IF_NONE_MATCH") else False ) if ( if_modified_since and if_none_match and if_none_match == etag # etag must match and if_modified_since == last_modified ): # if-modified-since must match php.header(php.SERVER["SERVER_PROTOCOL"] + " 304 Not Modified") # All 304 responses must send an etag if the 200 response for the same # object contained an etag php.header("Etag: %(etag)s" % {"etag": etag}) exit() # Send appropriate response: php.header("Last-Modified: %(last_modified)s" % {"last_modified": last_modified}) php.header("Etag: %(etag)s" % {"etag": etag}) # The following headers force validation of cache: php.header("Expires: Sun, 19 Nov 1978 05:00:00 GMT") php.header("Cache-Control: must-revalidate") if variable_get("page_compression", True): # Determine if the browser accepts gzipped data. if php.strpos(php.SERVER["HTTP_ACCEPT_ENCODING"], "gzip") == False and php.function_exists("gzencode"): # Strip the gzip php.header and run uncompress. cache.data = php.gzinflate(php.substr(php.substr(cache.data, 10), 0, -8)) elif php.function_exists("gzencode"): php.header("Content-Encoding: gzip") # Send the original request's headers. We send them one after # another so PHP's php.header() def can deal with duplicate # headers. headers = php.explode("\n", cache.headers) for php.header_ in headers: php.header(php.header_) print cache.data
def drupal_page_cache_header(cache): """ Set HTTP headers in preparation for a cached page response. The general approach here is that anonymous users can keep a local cache of the page, but must revalidate it on every request. Then, they are given a '304 Not Modified' response as long as they stay logged out and the page has not been modified. """ # Set default values: last_modified = php.gmdate('D, d M Y H:i:s', cache.created) + ' GMT' etag = '"' + drupy_md5(last_modified) + '"' # See if the client has provided the required HTTP headers: if_modified_since = (php.stripslashes(php.SERVER['HTTP_IF_MODIFIED_SINCE']) \ if php.isset(php.SERVER, 'HTTP_IF_MODIFIED_SINCE') else False) if_none_match = (php.stripslashes(php.SERVER['HTTP_IF_NONE_MATCH']) \ if php.isset(php.SERVER, 'HTTP_IF_NONE_MATCH') else False) if (if_modified_since and if_none_match and if_none_match == etag # etag must match and if_modified_since == last_modified): # if-modified-since must match php.header(php.SERVER['SERVER_PROTOCOL'] + ' 304 Not Modified') # All 304 responses must send an etag if the 200 response for the same # object contained an etag php.header("Etag: %(etag)s" % {'etag': etag}) exit() # Send appropriate response: php.header("Last-Modified: %(last_modified)s" % \ {'last_modified':last_modified}) php.header("Etag: %(etag)s" % {'etag': etag}) # The following headers force validation of cache: php.header("Expires: Sun, 19 Nov 1978 05:00:00 GMT") php.header("Cache-Control: must-revalidate") if (variable_get('page_compression', True)): # Determine if the browser accepts gzipped data. if (php.strpos(php.SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') == False and \ php.function_exists('gzencode')): # Strip the gzip php.header and run uncompress. cache.data = php.gzinflate( php.substr(php.substr(cache.data, 10), 0, -8)) elif (php.function_exists('gzencode')): php.header('Content-Encoding: gzip') # Send the original request's headers. We send them one after # another so PHP's php.header() def can deal with duplicate # headers. headers = php.explode("\n", cache.headers) for php.header_ in headers: php.header(php.header_) print cache.data
def request_uri(): """ Since php.SERVER['php.REQUEST_URI'] is only available on Apache, we generate an equivalent using other environment variables. """ if php.isset(php.SERVER, "REQUEST_URI"): uri = php.SERVER["REQUEST_URI"] else: if php.isset(php.SERVER, "argv"): uri = php.SERVER["SCRIPT_NAME"] + "?" + php.SERVER["argv"][0] elif php.isset(php.SERVER, "QUERY_STRING"): uri = php.SERVER["SCRIPT_NAME"] + "?" + php.SERVER["QUERY_STRING"] else: uri = php.SERVER["SCRIPT_NAME"] return uri
def request_uri(): """ Since php.SERVER['php.REQUEST_URI'] is only available on Apache, we generate an equivalent using other environment variables. """ if (php.isset(php.SERVER, 'REQUEST_URI')): uri = php.SERVER['REQUEST_URI'] else: if (php.isset(php.SERVER, 'argv')): uri = php.SERVER['SCRIPT_NAME'] + '?' + php.SERVER['argv'][0] elif (php.isset(php.SERVER, 'QUERY_STRING')): uri = php.SERVER['SCRIPT_NAME'] + '?' + php.SERVER['QUERY_STRING'] else: uri = php.SERVER['SCRIPT_NAME'] return uri
def language_list(field="language", reset=False): """ Get a list of languages set up indexed by the specified key @param field The field to index the list with. @param reset Boolean to request a reset of the list. """ php.static(language_list, "languages") # Reset language list if reset: languages_list.languages = {} # Init language list if languages_list.languages == None: if variable_get("language_count", 1) > 1 or plugin_exists("locale"): result = db_query("SELECT# FROM {languages} ORDER BY weight ASC, name ASC") while True: row = db_fetch_object(result) if row == None: break languages_list.languages["language"][row.language] = row else: # No locale plugin, so use the default language only. default_ = language_default() languages_list.languages["language"][default_.language] = default_ # Return the array indexed by the right field if not php.isset(languages_list.languages, field): languages_list.languages[field] = {} for lang in languages_list.languages["language"]: # Some values should be collected into an array if php.in_array(field, ["enabled", "weight"]): languages_list.languages[field][lang.field][lang.language] = lang else: languages_list.languages[field][lang.field] = lang return languages_list.languages[field]
def _process_field(field): """ Set database-engine specific properties for a field. @param field A field description array, as specified in the schema documentation. """ if (not php.isset(field, 'size')): field['size'] = 'normal' # Set the correct database-engine specific datatype. if (not php.isset(field, 'mysql_type')): map_ = db_type_map() field['mysql_type'] = map_[field['type'] + ':' + field['size']] if (field['type'] == 'serial'): field['auto_increment'] = True return field
def drupal_match_path(path_, patterns): """ Check if a path matches any pattern in a set of patterns. @note DRUPY: This function was substantially modified @param path The path to match. @param patterns String containing a set of patterns separated by \n, \r or \r\n. @return Boolean value: TRUE if the path matches a pattern, FALSE otherwise. """ php.static(drupal_match_path, 'regexps') if (not php.isset(drupal_match_path.regexps, patterns)): frnt = variable_get('site_frontpage', 'node') frnt_q = php.preg_quote(frnt, '/') frnt_p = '\1' + frnt_q + '\2' pra2 = ['|', '.*', frnt_p] pra1 = ['/(\r\n?|\n)/', '/\\\\\*/', '/(^|\|)\\\\<front\\\\>($|\|)/'] pat_q = php.preg_quote(patterns, '/') pat_prep = php.preg_replace(pra1, pra2, pat_q) pat_final = '/^(' + pat_prep + ')$/' drupal_match_path.regexps[patterns] = pat_final return (php.preg_match(drupal_match_path.regexps[patterns], path_) > 0) else: return False
def url_rewrite(path, options): """ Rewrite URL's with language based prefix. Parameters are the same as those of the url() function. """ # Only modify relative (insite) URLs. if (not options['external']): # Language can be passed as an option, or we go for current language. if (not php.isset(options, 'language')): options['language'] = lib_appglobals.language lang_type = variable_get('language_negotiation', \ lib_bootstrap.LANGUAGE_NEGOTIATION_NONE) if lang_type == lib_bootstrap.LANGUAGE_NEGOTIATION_NONE: # No language dependent path allowed in this mode. del (options['language']) return elif lang_type == lib_bootstrap.LANGUAGE_NEGOTIATION_DOMAIN: if (options['language'].domain): # Ask for an absolute URL with our modified base_url. options['absolute'] = True options['base_url'] = options['language'].domain return elif lang_type == lib_bootstrap.LANGUAGE_NEGOTIATION_PATH_DEFAULT: default = language_default() if (options['language'].language == default.language): return if lang_type == lib_bootstrap.LANGUAGE_NEGOTIATION_PATH: if (not php.empty(options['language'].prefix)): options['prefix'] = options['language'].prefix + '/' return
def drupal_get_messages(type=None, clear_queue=True): """ Return all messages that have been set. @param type (optional) Only return messages of this type. @param clear_queue (optional) Set to FALSE if you do not want to clear the messages queue @return An associative array, the key is the message type, the value an array of messages. If the type parameter is passed, you get only that type, or an empty array if there are no such messages. If type is not passed, all message types are returned, or an empty array if none exist. """ messages = drupal_set_message() if not php.empty("messages"): if type != None and type != False: if clear_queue: del (php.SESSION["messages"][type]) if php.isset(messages, type): return {type: messages[type]} else: if clear_queue: del (php.SESSION["messages"]) return messages return {}
def update_page(content, show_messages=True): """ Generate a themed update page. Note: this function is not themeable. @param content The page content to show. @param show_messages Whether to output status and error messages. False can be useful to postpone the messages to a subsequent page. """ # Set required headers. drupal_set_header('Content-Type: text/html; charset=utf-8') # Assign content and show message flag. variables['content'] = content variables['show_messages'] = show_messages # The maintenance preprocess function is recycled here. template_preprocess_maintenance_page(variables) # Special handling of warning messages. messages = drupal_set_message() if (php.isset(messages['warning'])): title = ('The following update warnings should be carefully ' + \ 'reviewed before continuing' if \ (php.count(messages['warning']) > 1) else \ 'The following update warning should be carefully ' + \ 'reviewed before continuing') variables['messages'] += '<h4>' + title + ':</h4>' variables['messages'] += theme('status_messages', 'warning') # This was called as a theme hook (not template), so we need to # fix path_to_theme() for the template, to point at the actual # theme rather than system plugin as owner of the hook. lib_appglobals.theme_path = 'themes/garland' return theme_render_template('themes/garland/maintenance-page.tpl.php', \ variables)
def timer_read(name): """ Read the current timer value without stopping the timer. @param name The name of the timer. @return The current timer value in ms. """ if php.isset(lib_appglobals.timers[name], "start"): (usec, sec) = php.explode(" ", php.microtime()) stop = float(usec) + float(sec) diff = round((stop - lib_appglobals.timers[name]["start"]) * 1000, 2) if php.isset(lib_appglobals.timers[name], "time"): diff += lib_appglobals.timers[name]["time"] return diff
def url_rewrite(path, options): """ Rewrite URL's with language based prefix. Parameters are the same as those of the url() function. """ # Only modify relative (insite) URLs. if (not options['external']): # Language can be passed as an option, or we go for current language. if (not php.isset(options, 'language')): options['language'] = lib_appglobals.language lang_type = variable_get('language_negotiation', \ lib_bootstrap.LANGUAGE_NEGOTIATION_NONE) if lang_type == lib_bootstrap.LANGUAGE_NEGOTIATION_NONE: # No language dependent path allowed in this mode. del(options['language']) return elif lang_type == lib_bootstrap.LANGUAGE_NEGOTIATION_DOMAIN: if (options['language'].domain): # Ask for an absolute URL with our modified base_url. options['absolute'] = True options['base_url'] = options['language'].domain return elif lang_type == lib_bootstrap.LANGUAGE_NEGOTIATION_PATH_DEFAULT: default = language_default() if (options['language'].language == default.language): return if lang_type == lib_bootstrap.LANGUAGE_NEGOTIATION_PATH: if (not php.empty(options['language'].prefix)): options['prefix'] = options['language'].prefix + '/' return
def update_page(content, show_messages = True): """ Generate a themed update page. Note: this function is not themeable. @param content The page content to show. @param show_messages Whether to output status and error messages. False can be useful to postpone the messages to a subsequent page. """ # Set required headers. drupal_set_header('Content-Type: text/html; charset=utf-8') # Assign content and show message flag. variables['content'] = content variables['show_messages'] = show_messages # The maintenance preprocess function is recycled here. template_preprocess_maintenance_page(variables) # Special handling of warning messages. messages = drupal_set_message() if (php.isset(messages['warning'])): title = ('The following update warnings should be carefully ' + \ 'reviewed before continuing' if \ (php.count(messages['warning']) > 1) else \ 'The following update warning should be carefully ' + \ 'reviewed before continuing') variables['messages'] += '<h4>' + title + ':</h4>' variables['messages'] += theme('status_messages', 'warning') # This was called as a theme hook (not template), so we need to # fix path_to_theme() for the template, to point at the actual # theme rather than system plugin as owner of the hook. lib_appglobals.theme_path = 'themes/garland' return theme_render_template('themes/garland/maintenance-page.tpl.php', \ variables)
def timer_read(name): """ Read the current timer value without stopping the timer. @param name The name of the timer. @return The current timer value in ms. """ if (php.isset(lib_appglobals.timers[name], 'start')): (usec, sec) = php.explode(' ', php.microtime()) stop = float(usec) + float(sec) diff = round((stop - lib_appglobals.timers[name]['start']) * 1000, 2) if (php.isset(lib_appglobals.timers[name], 'time')): diff += lib_appglobals.timers[name]['time'] return diff
def drupal_match_path(path_, patterns): """ Check if a path matches any pattern in a set of patterns. @note DRUPY: This function was substantially modified @param path The path to match. @param patterns String containing a set of patterns separated by \n, \r or \r\n. @return Boolean value: TRUE if the path matches a pattern, FALSE otherwise. """ php.static(drupal_match_path, 'regexps') if (not php.isset(drupal_match_path.regexps, patterns)): frnt = variable_get('site_frontpage', 'node'); frnt_q = php.preg_quote(frnt, '/'); frnt_p = '\1' + frnt_q + '\2'; pra2 = ['|', '.*', frnt_p]; pra1 = ['/(\r\n?|\n)/', '/\\\\\*/', '/(^|\|)\\\\<front\\\\>($|\|)/']; pat_q = php.preg_quote(patterns, '/'); pat_prep = php.preg_replace(pra1, pra2, pat_q); pat_final = '/^(' + pat_prep + ')$/'; drupal_match_path.regexps[patterns] = pat_final; return (php.preg_match(drupal_match_path.regexps[patterns], path_) > 0) else: return False
def drupal_get_messages(type=None, clear_queue=True): """ Return all messages that have been set. @param type (optional) Only return messages of this type. @param clear_queue (optional) Set to FALSE if you do not want to clear the messages queue @return An associative array, the key is the message type, the value an array of messages. If the type parameter is passed, you get only that type, or an empty array if there are no such messages. If type is not passed, all message types are returned, or an empty array if none exist. """ messages = drupal_set_message() if (not php.empty('messages')): if (type != None and type != False): if (clear_queue): del (php.SESSION['messages'][type]) if (php.isset(messages, type)): return { type: messages[type] } else: if (clear_queue): del (php.SESSION['messages']) return messages return {}
def header(cell, header, ts): """ Format a column header. If the cell in question is the column header for the current sort criterion, it gets special formatting. All possible sort criteria become links. @param cell The cell to format. @param header An array of column headers in the format described in theme_table(). @param ts The current table sort context as returned from hook_init(). @return A properly formatted cell, ready for _theme_table_cell(). """ # Special formatting for the currently sorted column header. if php.is_array(cell) and php.isset(cell['field']): title = t('sort by @s', {'@s': cell['data']}) if cell['data'] == ts['name']: ts['sort'] = ('desc' if (ts['sort'] == 'asc') else 'asc') if php.isset(cell['class']): cell['class'] += ' active' else: cell['class'] = 'active' image = lib_theme.theme('tablesort_indicator', ts['sort']) else: # If the user clicks a different header, we want to sort ascending # initially. ts['sort'] = 'asc' image = '' if not php.empty(ts['query_string']): ts['query_string'] = '&' + ts['query_string'] cell['data'] = l( cell['data'] + image, php.GET['q'], { 'attributes': { 'title': title, 'query': 'sort=' + ts['sort'] + '&order=' + rawurlencode(cell['data']) + ts['query_string'], 'html': TRUE } } ) php.unset(cell['field'], cell['sort']) return cell
def add_field(ret, table, field, spec, keys_new=[]): """ Add a new field to a table. @param ret Array to which query results will be added. @param table Name of the table to be altered. @param field Name of the field to be added. @param spec The field specification array, as taken from a schema definition. The specification may also contain the key 'initial', the newly created field will be set to the value of the key in all rows. This is most useful for creating NOT None columns with no default value in existing tables. @param keys_new Optional keys and indexes specification to be created on the table along with adding the field. The format is the same as a table specification but without the 'fields' element. If you are adding a type 'serial' field, you MUST specify at least one key or index including it in this array. @see db_change_field for more explanation why. """ php.Reference.check(ret) fixNone = False if (not php.empty(spec['not None']) and not php.isset(spec, 'default')): fixNone = True spec['not None'] = False query = 'ALTER TABLE {' + table + '} ADD ' query += _db_create_field_sql(field, _db_process_field(spec)) if (php.count(keys_new)): query += ', ADD ' + php.implode(', ADD ', _db_create_keys_sql(keys_new)) ret.append(update_sql(query)) if (php.isset(spec, 'initial')): # All this because update_sql does not support %-placeholders. sql = 'UPDATE {' + table + '} SET ' + field + ' = ' + \ db_type_placeholder(spec['type']) result = db_query(sql, spec['initial']) ret.append( {'success' : result != False, \ 'query' : check_plain(sql + ' (' + spec['initial'] + ')')}) if (fixNone): spec['not None'] = True db_change_field(ret, table, field, field, spec)
def timer_start(name): """ Start the timer with the specified name. If you start and stop the same timer multiple times, the measured intervals will be accumulated. @param name The name of the timer. """ if lib_appglobals.timers == None: lib_appglobals.timers = {} if not php.isset(lib_appglobals.timers, name): lib_appglobals.timers[name] = {} (usec, sec) = php.explode(" ", php.microtime()) lib_appglobals.timers[name]["start"] = float(usec) + float(sec) lib_appglobals.timers[name]["count"] = ( (lib_appglobals.timers[name]["count"] + 1) if php.isset(lib_appglobals.timers[name], "count") else 1 )
def drupal_init_path(): """ Initialize the php.GET['q'] variable to the proper normal path. """ if (php.isset(php.GET, 'q') and not php.empty(php.GET['q'])): php.GET['q'] = drupal_get_normal_path(php.trim(php.GET['q'], '/')) else: php.GET['q'] = drupal_get_normal_path( \ lib_bootstrap.variable_get('site_frontpage', 'node'))
def timer_start(name): """ Start the timer with the specified name. If you start and stop the same timer multiple times, the measured intervals will be accumulated. @param name The name of the timer. """ if lib_appglobals.timers == None: lib_appglobals.timers = {} if not php.isset(lib_appglobals.timers, name): lib_appglobals.timers[name] = {} (usec, sec) = php.explode(' ', php.microtime()) lib_appglobals.timers[name]['start'] = float(usec) + float(sec) lib_appglobals.timers[name]['count'] = \ ((lib_appglobals.timers[name]['count'] + 1) if \ php.isset(lib_appglobals.timers[name],'count') else 1)
def add_field(ret, table, field, spec, keys_new = []): """ Add a new field to a table. @param ret Array to which query results will be added. @param table Name of the table to be altered. @param field Name of the field to be added. @param spec The field specification array, as taken from a schema definition. The specification may also contain the key 'initial', the newly created field will be set to the value of the key in all rows. This is most useful for creating NOT None columns with no default value in existing tables. @param keys_new Optional keys and indexes specification to be created on the table along with adding the field. The format is the same as a table specification but without the 'fields' element. If you are adding a type 'serial' field, you MUST specify at least one key or index including it in this array. @see db_change_field for more explanation why. """ php.Reference.check(ret) fixNone = False if (not php.empty(spec['not None']) and not php.isset(spec, 'default')): fixNone = True spec['not None'] = False query = 'ALTER TABLE {' + table + '} ADD ' query += _db_create_field_sql(field, _db_process_field(spec)) if (php.count(keys_new)): query += ', ADD ' + php.implode(', ADD ', _db_create_keys_sql(keys_new)) ret.append( update_sql(query) ) if (php.isset(spec, 'initial')): # All this because update_sql does not support %-placeholders. sql = 'UPDATE {' + table + '} SET ' + field + ' = ' + \ db_type_placeholder(spec['type']) result = db_query(sql, spec['initial']) ret.append( {'success' : result != False, \ 'query' : check_plain(sql + ' (' + spec['initial'] + ')')}) if (fixNone): spec['not None'] = True db_change_field(ret, table, field, field, spec)
def initialize(): """ Choose a language for the page, based on language negotiation settings. """ # Configured presentation language mode. mode = variable_get('language_negotiation', \ lib_bootstrap.LANGUAGE_NEGOTIATION_NONE) # Get a list of enabled languages. languages = lib_bootstrap.language_list('enabled') languages = languages[1] if mode == lib_bootstrap.LANGUAGE_NEGOTIATION_NONE: return language_default() elif mode == lib_bootstrap.LANGUAGE_NEGOTIATION_DOMAIN: for language in languages: parts = php.parse_url(language.domain) if (not php.empty(parts['host']) and \ (php.SERVER['php.SERVER_NAME'] == parts['host'])): return language return language_default() elif mode == lib_bootstrap.LANGUAGE_NEGOTIATION_PATH_DEFAULT or \ mode == lib_bootstrap.LANGUAGE_NEGOTIATION_PATH: # _GET['q'] might not be available at this time, because # path initialization runs after the language bootstrap phase. args = (php.explode('/', _GET['q']) if php.isset(_GET, 'q') else []) prefix = php.array_shift(args) # Search prefix within enabled languages. for language in languages: if (not php.empty(language.prefix) and language.prefix == prefix): # Rebuild php.GET['q'] with the language removed. php.GET['q'] = php.implode('/', args) return language if (mode == LANGUAGE_NEGOTIATION_PATH_DEFAULT): # If we did not found the language by prefix, choose the default. return language_default() # User language. if (lib_appglobals.user.uid and \ php.isset(languages[lib_appglobals.user.language])): return languages[lib_appglobals.user.language] # Browser accept-language parsing. language = language_from_browser() if (language): return language # Fall back on the default if everything else fails. return language_default()
def set_active(name = 'default'): """ Activate a database for future queries. If it is necessary to use external databases in a project, this function can be used to change where database queries are sent. If the database has not yet been used, it is initialized using the URL specified for that name in Drupal's configuration file. If this name is not defined, a duplicate of the default connection is made instead. Be sure to change the connection back to the default when done with custom code. @param name The name assigned to the newly active database connection. If omitted, the default connection will be made active. @return the name of the previously active database or FALSE if non was found. @todo BC: Need to eventually resolve the database importing mechanism here right now we are statically loading mysql at the top, but eventually we need to get this figured out """ php.static(set_active, 'db_conns', {}) php.static(set_active, 'active_name', False) if (settings.db_url == None): install_goto('install.py'); if (not php.isset(set_active.db_conns, name)): # Initiate a new connection, using the named DB URL specified. if (isinstance(settings.db_url, dict)): connect_url = (settings.db_url[name] if \ php.array_key_exists(name, settings.db_url) else \ settings.db_url['default']); else: connect_url = settings.db_url; lib_appglobals.db_type = \ php.substr(connect_url, 0, php.strpos(connect_url, '://')); #handler = "includes/database_%(db_type)s.py" % {'db_type' : db_type}; #try: # import db file here #except ImportError: # _db_error_page("The database type '" + db_type + \ # "' is unsupported. Please use either 'mysql' or " + \ # "'mysqli' for MySQL, or 'pgsql' for PostgreSQL databases."); set_active.db_conns[name] = db.connect(connect_url); # We need to pass around the simpletest database prefix in the request # and we put that in the user_agent php.header. if (php.preg_match("/^simpletest\d+$/", php.SERVER['HTTP_USER_AGENT'])): settings.db_prefix = php.SERVER['HTTP_USER_AGENT']; previous_name = set_active.active_name; # Set the active connection. set_active.active_name = name; lib_appglobals.active_db = set_active.db_conns[name]; return previous_name;
def write(key, value): # If saving of session data is disabled or if the client # doesn't have a session, # and one isn't being created ($value), do nothing. # This keeps crawlers out of # the session table. This reduces memory and server load, # and gives more useful # statistics. We can't eliminate anonymous session table rows # without breaking # the "Who's Online" block. if (not session_save_session() or \ (php.empty(php.COOKIE[php.session_name()]) and php.empty(value))): return True result = db_result(db_query("SELECT COUNT(*) FROM {sessions} " + \ "WHERE sid = '%s'", key)) lib_database.query(\ "UPDATE {sessions} SET " + \ "uid = %d, cache = %d, hostname = '%s', " + \ "session = '%s', timestamp = %d WHERE sid = '%s'", \ lib_appglobals.user.uid, (lib_appglobals.user.cache if \ php.isset(lib_appglobals.user.cache) else ''), \ ip_address(), value, php.time_(), key) if (lib_database.affected_rows()): # Last access time is updated no more frequently than once # every 180 seconds. # This reduces contention in the users table. if (lib_appglobals.user.uid and \ drupy_time() - lib_appglobals.user.access > \ variable_get('session_write_interval', 180)): db_query("UPDATE {users} SET access = %d WHERE uid = %d", \ php.time_(), lib_appglobals.user.uid) else: # If this query fails, another parallel request probably got here first. # In that case, any session data generated in this request is discarded. lib_databae.query(\ "INSERT INTO {sessions} " + \ "(sid, uid, cache, hostname, session, timestamp) " + \ "VALUES ('%s', %d, %d, '%s', '%s', %d)", \ key, lib_appglobals.user.uid, (lib_appglobals.user.cache if \ php.isset(lib_appglobals.user.cache) else ''), \ ip_address(), value, php.time_()) return True
def exists(plugin_): """ Determine whether a given plugin exists. @param plugin The name of the plugin (without the .plugin extension). @return True if the plugin is both installed and enabled. """ list_ = plugin_list() return php.isset(list_, plugin_)
def _rewrite_sql(query = '', primary_table = 'n', primary_field = 'nid', \ args = []): where = [] join_ = [] distinct = False for plugin in lib_plugin.implements('db_rewrite_sql'): result = lib_plugin.invoke(plugin, 'db_rewrite_sql', query, \ primary_table, primary_field, args) if (php.isset(result) and php.is_array(result)): if (php.isset(result['where'])): where.append( result['where'] ) if (php.isset(result['join'])): join_.append( result['join'] ) if (php.isset(result['distinct']) and result['distinct']): distinct = True elif (php.isset(result)): where.append( result ) where = ('' if php.empty(where) else \ ('(' + php.implode(') AND (', where) + ')') ) join_ = ('' if php.empty(join) else php.implode(' ', join)) return (join, where, distinct)
def variable_get(name, default_): """ Return a persistent variable. @param name The name of the variable to return. @param default The default value to use if this variable has never been set. @return The value of the variable. """ return settings.conf[name] if php.isset(settings.conf, name) else default_
def get_order(headers): """ Determine the current sort criterion. @param headers An array of column headers in the format described in theme_table(). @return An associative array describing the criterion, containing the keys: - "name": The localized title of the table column. - "sql": The name of the database field to sort on. """ order = php.GET['order'] if php.isset(php.GET['order']) else '' for header in headers: if php.isset(header['data']) and order == header['data']: return { 'name': header['data'], 'sql': header['field'] if php.isset(header['field']) else '' } if (php.isset(header['sort']) and (header['sort'] == 'asc' or header['sort'] == 'desc')): default = { 'name': header['data'], 'sql': header['field'] if php.isset(header['field']) else '' } if php.isset(default): return default else: # The first column specified is initial 'order by' field unless otherwise # specified if php.is_array(headers[0]): headers[0] += {'data': None, 'field': None} return {'name': headers[0]['data'], 'sql': headers[0]['field']} else: return {'name': headers[0]}
def variable_get(name, default_): """ Return a persistent variable. @param name The name of the variable to return. @param default The default value to use if this variable has never been set. @return The value of the variable. """ return (settings.conf[name] if php.isset(settings.conf, name) else default_)
def drupal_get_schema(table=None, rebuild=False): """ Get the schema definition of a table, or the whole database schema. The returned schema will include any modifications made by any module that implements hook_schema_alter(). @param $table The name of the table. If not given, the schema of all tables is returned. @param $rebuild If true, the schema will be rebuilt instead of retrieved from the cache. """ php.static(drupal_get_schema, 'schema', []) if (php.empty(drupal_get_schema.schema) or rebuild): # Try to load the schema from cache. cached = lib_cache.get('schema') if (not rebuild and cached): drupal_get_schema.schema = cached.data # Otherwise, rebuild the schema cache. else: drupal_get_schema.schema = [] # Load the .install files to get hook_schema. # On some databases this function may be called before bootstrap has # been completed, so we force the functions we need to load just in case. if (drupal_function_exists('module_load_all_includes')): # There is currently a bug in module_list() where it caches what it # was last called with, which is not always what you want. # module_load_all_includes() calls module_list(), but if this function # is called very early in the bootstrap process then it will be # uninitialized and therefore return no modules. Instead, we have to # "prime" module_list() here to to values we want, specifically # "yes rebuild the list and don't limit to bootstrap". # TODO: Remove this call after http://drupal.org/node/222109 is fixed. lib_plugin.list(True, False) lib_plugin.load_all_includes('install') # Invoke hook_schema for all modules. for module in module_implements('schema'): current = lib_plugin.invoke(module, 'schema') if (drupal_function_exists('_drupal_initialize_schema')): _drupal_initialize_schema(module, current) schema = php.array_merge(schema, current) if (drupal_function_exists('drupal_alter')): drupal_alter('schema', schema) if (drupal_get_bootstrap_phase() == DRUPAL_BOOTSTRAP_FULL): cache_set('schema', schema) if (table is None): return schema elif (php.isset(schema, table)): return schema[table] else: return False