protected function _GetData() { $Px = Gdn::database()->DatabasePrefix; $Sql = "show table status where Name in ('{$Px}User', '{$Px}Discussion', '{$Px}Comment')"; $Result = array('User' => 0, 'Discussion' => 0, 'Comment' => 0); foreach ($Result as $Name => $Value) { $Result[$Name] = $this->getCount($Name); } $this->setData('Totals', $Result); }
/** * The constructor for this class. Automatically fills $this->ClassName. * * @param string $Database * @todo $Database needs a description. */ public function __construct($Database = null) { parent::__construct(); if (is_null($Database)) { $this->Database = Gdn::database(); } else { $this->Database = $Database; } $this->databasePrefix($this->Database->DatabasePrefix); $this->reset(); }
/** * Write information about addons to the discussion if it is related to an addon. * * @param DiscussionController $Sender */ public function discussionController_afterDiscussionTitle_handler($Sender) { $Discussion = $Sender->data('Discussion'); $AddonID = val('AddonID', $Discussion); if (is_numeric($AddonID) && $AddonID > 0) { $Data = Gdn::database()->sql()->select('Name')->from('Addon')->where('AddonID', $AddonID)->get()->firstRow(); if ($Data) { echo renderDiscussionAddonWarning($AddonID, $Data->Name, val('DiscussionID', $Discussion)); } } }
/** * Class constructor. Defines the related database table name. * * @param string $Name An optional parameter that allows you to explicitly define the name of * the table that this model represents. You can also explicitly set this value with $this->Name. */ public function __construct($Name = '') { if ($Name == '') { $Name = get_class($this); } $this->Database = Gdn::database(); $this->SQL = $this->Database->SQL(); $this->Validation = new Gdn_Validation(); $this->Name = $Name; $this->PrimaryKey = $Name . 'ID'; parent::__construct(); }
/** * The constructor for this class. Automatically fills $this->ClassName. * * @param string $Database * @todo $Database needs a description. */ public function __construct($Database = null) { parent::__construct(); if (is_null($Database)) { $this->Database = Gdn::database(); } else { $this->Database = $Database; } $this->databasePrefix($this->Database->DatabasePrefix); $this->setAlterTableThreshold(c('Database.AlterTableThreshold', 0)); $this->reset(); }
/** * Class constructor. Defines the related database table name. * * @param string $Name An optional parameter that allows you to explicitly define the name of * the table that this model represents. You can also explicitly set this value with $this->Name. */ public function __construct($Name = '') { if ($Name == '') { $Name = get_class($this); } $this->Database = Gdn::database(); $this->SQL = $this->Database->SQL(); $this->Validation = new Gdn_Validation(); $this->Name = $Name; $this->PrimaryKey = $Name . 'ID'; $this->filterFields = array('Attributes' => 0, 'DateInserted' => 0, 'InsertUserID' => 0, 'InsertIPAddress' => 0, 'CheckBoxes' => 0, 'DateUpdated' => 0, 'UpdateUserID' => 0, 'UpdateIPAddress' => 0, 'DeliveryMethod' => 0, 'DeliveryType' => 0, 'OK' => 0, 'TransientKey' => 0, 'hpt' => 0); parent::__construct(); }
/** * Export core Vanilla and Conversations tables. * * @since 2.0.0 * @access public */ public function export() { $this->permission('Garden.Export'); // This permission doesn't exist, so only users with Admin == '1' will succeed. set_time_limit(60 * 2); $Ex = new ExportModel(); $Ex->pdo(Gdn::database()->connection()); $Ex->Prefix = Gdn::database()->DatabasePrefix; /// 2. Do the export. /// $Ex->UseCompression = true; $Ex->beginExport(PATH_ROOT . DS . 'uploads' . DS . 'export ' . date('Y-m-d His') . '.txt.gz', 'Vanilla 2.0'); $Ex->exportTable('User', 'select * from :_User'); // ":_" will be replace by database prefix $Ex->exportTable('Role', 'select * from :_Role'); $Ex->exportTable('UserRole', 'select * from :_UserRole'); $Ex->exportTable('Category', 'select * from :_Category'); $Ex->exportTable('Discussion', 'select * from :_Discussion'); $Ex->exportTable('Comment', 'select * from :_Comment'); $Ex->exportTable('Conversation', 'select * from :_Conversation'); $Ex->exportTable('UserConversation', 'select * from :_UserConversation'); $Ex->exportTable('ConversationMessage', 'select * from :_ConversationMessage'); $Ex->endExport(); }
/** * Registration that requires approval. * * Events: RegistrationPending * * @access private * @since 2.0.0 */ private function registerApproval() { Gdn::userModel()->addPasswordStrength($this); // If the form has been posted back... if ($this->Form->isPostBack()) { // Add validation rules that are not enforced by the model $this->UserModel->defineSchema(); $this->UserModel->Validation->applyRule('Name', 'Username', $this->UsernameError); $this->UserModel->Validation->applyRule('TermsOfService', 'Required', t('You must agree to the terms of service.')); $this->UserModel->Validation->applyRule('Password', 'Required'); $this->UserModel->Validation->applyRule('Password', 'Strength'); $this->UserModel->Validation->applyRule('Password', 'Match'); $this->UserModel->Validation->applyRule('DiscoveryText', 'Required', 'Tell us why you want to join!'); // $this->UserModel->Validation->applyRule('DateOfBirth', 'MinimumAge'); $this->fireEvent('RegisterValidation'); try { $Values = $this->Form->formValues(); $Values = $this->UserModel->filterForm($Values, true); unset($Values['Roles']); $AuthUserID = $this->UserModel->register($Values); $this->setData('UserID', $AuthUserID); if (!$AuthUserID) { $this->Form->setValidationResults($this->UserModel->validationResults()); } else { // The user has been created successfully, so sign in now. Gdn::session()->start($AuthUserID); if ($this->Form->getFormValue('RememberMe')) { Gdn::authenticator()->SetIdentity($AuthUserID, true); } // Notification text $Label = t('NewApplicantEmail', 'New applicant:'); $Story = anchor(Gdn_Format::text($Label . ' ' . $Values['Name']), ExternalUrl('dashboard/user/applicants')); $this->EventArguments['AuthUserID'] = $AuthUserID; $this->EventArguments['Story'] =& $Story; $this->fireEvent('RegistrationPending'); $this->View = "RegisterThanks"; // Tell the user their application will be reviewed by an administrator. // Grab all of the users that need to be notified. $Data = Gdn::database()->sql()->getWhere('UserMeta', array('Name' => 'Preferences.Email.Applicant'))->resultArray(); $ActivityModel = new ActivityModel(); foreach ($Data as $Row) { $ActivityModel->add($AuthUserID, 'Applicant', $Story, $Row['UserID'], '', '/dashboard/user/applicants', 'Only'); } } } catch (Exception $Ex) { $this->Form->addError($Ex); } $this->render(); } else { $this->render(); } }
/** * Allows the configuration of basic setup information in Garden. This * should not be functional after the application has been set up. * * @since 2.0.0 * @access public * @param string $RedirectUrl Where to send user afterward. */ private function configure($RedirectUrl = '') { // Create a model to save configuration settings $Validation = new Gdn_Validation(); $ConfigurationModel = new Gdn_ConfigurationModel($Validation); $ConfigurationModel->setField(array('Garden.Locale', 'Garden.Title', 'Garden.WebRoot', 'Garden.Cookie.Salt', 'Garden.Cookie.Domain', 'Database.Name', 'Database.Host', 'Database.User', 'Database.Password', 'Garden.Registration.ConfirmEmail', 'Garden.Email.SupportName')); // Set the models on the forms. $this->Form->setModel($ConfigurationModel); // If seeing the form for the first time... if (!$this->Form->isPostback()) { // Force the webroot using our best guesstimates $ConfigurationModel->Data['Database.Host'] = 'localhost'; $this->Form->setData($ConfigurationModel->Data); } else { // Define some validation rules for the fields being saved $ConfigurationModel->Validation->applyRule('Database.Name', 'Required', 'You must specify the name of the database in which you want to set up Vanilla.'); // Let's make some user-friendly custom errors for database problems $DatabaseHost = $this->Form->getFormValue('Database.Host', '~~Invalid~~'); $DatabaseName = $this->Form->getFormValue('Database.Name', '~~Invalid~~'); $DatabaseUser = $this->Form->getFormValue('Database.User', '~~Invalid~~'); $DatabasePassword = $this->Form->getFormValue('Database.Password', '~~Invalid~~'); $ConnectionString = GetConnectionString($DatabaseName, $DatabaseHost); try { $Connection = new PDO($ConnectionString, $DatabaseUser, $DatabasePassword); } catch (PDOException $Exception) { switch ($Exception->getCode()) { case 1044: $this->Form->addError(t('The database user you specified does not have permission to access the database. Have you created the database yet? The database reported: <code>%s</code>'), strip_tags($Exception->getMessage())); break; case 1045: $this->Form->addError(t('Failed to connect to the database with the username and password you entered. Did you mistype them? The database reported: <code>%s</code>'), strip_tags($Exception->getMessage())); break; case 1049: $this->Form->addError(t('It appears as though the database you specified does not exist yet. Have you created it yet? Did you mistype the name? The database reported: <code>%s</code>'), strip_tags($Exception->getMessage())); break; case 2005: $this->Form->addError(t("Are you sure you've entered the correct database host name? Maybe you mistyped it? The database reported: <code>%s</code>"), strip_tags($Exception->getMessage())); break; default: $this->Form->addError(sprintf(t('ValidateConnection'), strip_tags($Exception->getMessage()))); break; } } $ConfigurationModel->Validation->applyRule('Garden.Title', 'Required'); $ConfigurationFormValues = $this->Form->formValues(); if ($ConfigurationModel->validate($ConfigurationFormValues) !== true || $this->Form->errorCount() > 0) { // Apply the validation results to the form(s) $this->Form->setValidationResults($ConfigurationModel->validationResults()); } else { $Host = array_shift(explode(':', Gdn::request()->requestHost())); $Domain = Gdn::request()->domain(); // Set up cookies now so that the user can be signed in. $ExistingSalt = c('Garden.Cookie.Salt', false); $ConfigurationFormValues['Garden.Cookie.Salt'] = $ExistingSalt ? $ExistingSalt : betterRandomString(16, 'Aa0'); $ConfigurationFormValues['Garden.Cookie.Domain'] = ''; // Don't set this to anything by default. # Tim - 2010-06-23 // Additional default setup values. $ConfigurationFormValues['Garden.Registration.ConfirmEmail'] = true; $ConfigurationFormValues['Garden.Email.SupportName'] = $ConfigurationFormValues['Garden.Title']; $ConfigurationModel->save($ConfigurationFormValues, true); // If changing locale, redefine locale sources: $NewLocale = 'en-CA'; // $this->Form->getFormValue('Garden.Locale', false); if ($NewLocale !== false && Gdn::config('Garden.Locale') != $NewLocale) { $Locale = Gdn::locale(); $Locale->set($NewLocale); } // Install db structure & basic data. $Database = Gdn::database(); $Database->init(); $Drop = false; $Explicit = false; try { include PATH_APPLICATIONS . DS . 'dashboard' . DS . 'settings' . DS . 'structure.php'; } catch (Exception $ex) { $this->Form->addError($ex); } if ($this->Form->errorCount() > 0) { return false; } // Create the administrative user $UserModel = Gdn::userModel(); $UserModel->defineSchema(); $UsernameError = t('UsernameError', 'Username can only contain letters, numbers, underscores, and must be between 3 and 20 characters long.'); $UserModel->Validation->applyRule('Name', 'Username', $UsernameError); $UserModel->Validation->applyRule('Name', 'Required', t('You must specify an admin username.')); $UserModel->Validation->applyRule('Password', 'Required', t('You must specify an admin password.')); $UserModel->Validation->applyRule('Password', 'Match'); $UserModel->Validation->applyRule('Email', 'Email'); if (!($AdminUserID = $UserModel->SaveAdminUser($ConfigurationFormValues))) { $this->Form->setValidationResults($UserModel->validationResults()); } else { // The user has been created successfully, so sign in now. saveToConfig('Garden.Installed', true, array('Save' => false)); Gdn::session()->start($AdminUserID, true); saveToConfig('Garden.Installed', false, array('Save' => false)); } if ($this->Form->errorCount() > 0) { return false; } // Assign some extra settings to the configuration file if everything succeeded. $ApplicationInfo = array(); include CombinePaths(array(PATH_APPLICATIONS . DS . 'dashboard' . DS . 'settings' . DS . 'about.php')); // Detect Internet connection for CDNs $Disconnected = !(bool) @fsockopen('ajax.googleapis.com', 80); saveToConfig(array('Garden.Version' => val('Version', val('Dashboard', $ApplicationInfo, array()), 'Undefined'), 'Garden.Cdns.Disable' => $Disconnected, 'Garden.CanProcessImages' => function_exists('gd_info'), 'EnabledPlugins.GettingStarted' => 'GettingStarted', 'EnabledPlugins.HtmLawed' => 'HtmLawed')); } } return $this->Form->errorCount() == 0 ? true : false; }
/** * Run a query, replacing database prefixes. * * @param string $Sql The sql to execute. * - :_z will be replaced by the import prefix. * - :_ will be replaced by the database prefix. * @param array $Parameters PDO parameters to pass to the query. * @return Gdn_DataSet */ public function query($Sql, $Parameters = null) { $Db = Gdn::database(); // Replace db prefixes. $Sql = str_replace(array(':_z', ':_'), array($Db->DatabasePrefix . self::TABLE_PREFIX, $Db->DatabasePrefix), $Sql); // Figure out the type of the type of the query. if (stringBeginsWith($Sql, 'select')) { $Type = 'select'; } elseif (stringBeginsWith($Sql, 'truncate')) { $Type = 'truncate'; } elseif (stringBeginsWith($Sql, 'insert')) { $Type = 'insert'; } elseif (stringBeginsWith($Sql, 'update')) { $Type = 'update'; } elseif (stringBeginsWith($Sql, 'delete')) { $Type = 'delete'; } else { $Type = 'select'; } // Execute the query. if (is_array($Parameters)) { $this->SQL->namedParameters($Parameters); } $Result = $this->SQL->query($Sql, $Type); //$this->Timer->Split('Sql: '. str_replace("\n", "\n ", $Sql)); return $Result; }
<?php if (!defined('APPLICATION')) { exit; } /** * Vanilla stub content for a new forum. * * Called by VanillaHooks::Setup() to insert stub content upon enabling app. * * @copyright 2009-2016 Vanilla Forums Inc. * @license http://www.opensource.org/licenses/gpl-2.0.php GNU GPL v2 * @since 2.0 * @package Vanilla */ $SQL = Gdn::database()->sql(); // Only do this once, ever. $Row = $SQL->get('Discussion', '', 'asc', 1)->firstRow(DATASET_TYPE_ARRAY); if ($Row) { return; } $DiscussionModel = new DiscussionModel(); // Prep default content $DiscussionTitle = "BAM! You’ve got a sweet forum"; $DiscussionBody = "There’s nothing sweeter than a fresh new forum, ready to welcome your community. A Vanilla Forum has all the bits and pieces you need to build an awesome discussion platform customized to your needs. Here’s a few tips:\n<ul>\n <li>Use the <a href=\"/dashboard/settings/gettingstarted\">Getting Started</a> list in the Dashboard to configure your site.</li>\n <li>Don’t use too many categories. We recommend 3-8. Keep it simple!</li>\n <li>“Announce” a discussion (click the gear) to stick to the top of the list, and “Close” it to stop further comments.</li>\n <li>Use “Sink” to take attention away from a discussion. New comments will no longer bring it back to the top of the list.</li>\n <li>Bookmark a discussion (click the star) to get notifications for new comments. You can edit notification settings from your profile.</li>\n</ul>\nGo ahead and edit or delete this discussion, then spread the word to get this place cooking. Cheers!"; $CommentBody = "This is the first comment on your site and it’s an important one.\n\nDon’t see your must-have feature? We keep Vanilla nice and simple by default. Use <b>addons</b> to get the special sauce your community needs.\n\nNot sure which addons to enable? Our favorites are Button Bar and Tagging. They’re almost always a great start."; $WallBody = "Ping! An activity post is a public way to talk at someone. When you update your status here, it posts it on your activity feed."; // Prep content meta data $SystemUserID = Gdn::userModel()->GetSystemUserID(); $TargetUserID = Gdn::session()->UserID; $Now = Gdn_Format::toDateTime();
echo '<h3><strong>Backtrace:</strong></h3> <div class="PreContainer">'; $BacktraceCount = count($Backtrace); $Odd = FALSE; for ($i = 0; $i < $BacktraceCount; ++$i) { echo '<pre' . ($Odd === FALSE ? '' : ' class="Odd"') . '>'; if (array_key_exists('file', $Backtrace[$i])) { $File = '[' . $Backtrace[$i]['file'] . ':' . $Backtrace[$i]['line'] . '] '; } echo $File, '<strong>', array_key_exists('class', $Backtrace[$i]) ? $Backtrace[$i]['class'] : 'PHP', array_key_exists('type', $Backtrace[$i]) ? $Backtrace[$i]['type'] : '::', $Backtrace[$i]['function'], '();</strong>', "</pre>\n"; $Odd = $Odd == TRUE ? FALSE : TRUE; } echo "</div>\n"; } // Dump queries if present. $Database = Gdn::database(); if (!is_null($Database) && method_exists($Database, 'Queries')) { $Queries = $Database->Queries(); $QueryTimes = $Database->QueryTimes(); if (count($Queries) > 0) { echo '<h3><strong>Queries:</strong></h3> <div class="PreContainer">'; $Odd = FALSE; foreach ($Queries as $Key => $QueryInfo) { $Query = $QueryInfo['Sql']; // this is a bit of a kludge. I found that the regex below would mess up when there were incremented named parameters. Ie. it would replace :Param before :Param0, which ended up with some values like "'4'0". $tmp = (array) $QueryInfo['Parameters']; arsort($tmp); foreach ($tmp as $Name => $Parameter) { $Pattern = '/(.+)(' . $Name . ')([\\W\\s]*)(.*)/'; $Replacement = "\$1'" . htmlentities($Parameter, ENT_COMPAT, 'UTF-8') . "'\$3\$4";
/** * * * @param $TokenKey * @param null $Nonce * @return bool */ public function lookupNonce($TokenKey, $Nonce = null) { $NonceData = Gdn::database()->sql()->select('uan.*')->from('UserAuthenticationNonce uan')->where('uan.Token', $TokenKey)->get()->firstRow(DATASET_TYPE_ARRAY); if ($NonceData && (is_null($Nonce) || $NonceData['Nonce'] == $Nonce)) { return $NonceData['Nonce']; } return false; }
/** * Database & config changes to be done upon enable. * * @since 2.0.0 * @access public */ public function setup() { $Database = Gdn::database(); $Config = Gdn::factory(Gdn::AliasConfig); $Drop = false; //c('Conversations.Version') === FALSE ? TRUE : FALSE; $Validation = new Gdn_Validation(); // This is going to be needed by structure.php to validate permission names include PATH_APPLICATIONS . DS . 'conversations' . DS . 'settings' . DS . 'structure.php'; include PATH_APPLICATIONS . DS . 'conversations' . DS . 'settings' . DS . 'stub.php'; $ApplicationInfo = array(); include combinePaths(array(PATH_APPLICATIONS . DS . 'conversations' . DS . 'settings' . DS . 'about.php')); $Version = val('Version', val('Conversations', $ApplicationInfo, array()), 'Undefined'); saveToConfig('Conversations.Version', $Version); }
/** * * * @param null $AddonCode * @param bool $Explicit * @param bool $Drop * @throws Exception */ public function runStructure($AddonCode = null, $Explicit = false, $Drop = false) { // Get the structure files for all of the enabled applications. $ApplicationManager = new Gdn_ApplicationManager(); $Apps = $ApplicationManager->EnabledApplications(); $AppNames = consolidateArrayValuesByKey($Apps, 'Folder'); $Paths = array(); foreach ($Apps as $Key => $AppInfo) { $Path = PATH_APPLICATIONS . "/{$AppInfo['Folder']}/settings/structure.php"; if (file_exists($Path)) { $Paths[] = $Path; } Gdn::ApplicationManager()->RegisterPermissions($Key, $this->Validation); } // Execute the structures. $Database = Gdn::database(); $SQL = Gdn::sql(); $Structure = Gdn::structure(); foreach ($Paths as $Path) { include $Path; } // Execute the structures for all of the plugins. $PluginManager = Gdn::pluginManager(); $Registered = $PluginManager->RegisteredPlugins(); foreach ($Registered as $ClassName => $Enabled) { if (!$Enabled) { continue; } try { $Plugin = $PluginManager->GetPluginInstance($ClassName, Gdn_PluginManager::ACCESS_CLASSNAME); if (method_exists($Plugin, 'Structure')) { trace("{$ClassName}->Structure()"); $Plugin->Structure(); } } catch (Exception $Ex) { // Do nothing, plugin wouldn't load/structure. if (Debug()) { throw $Ex; } } } $this->fireEvent('AfterStructure'); }
/** * Serves a file to the browser. * * @param string $File Full path to the file being served. * @param string $Name Name to give the file being served. Including extension overrides $File extension. Uses $File filename if empty. * @param string $MimeType The mime type of the file. * @param string $ServeMode Whether to download the file as an attachment, or inline */ public static function serveFile($File, $Name = '', $MimeType = '', $ServeMode = 'attachment') { $FileIsLocal = substr($File, 0, 4) == 'http' ? false : true; $FileAvailable = $FileIsLocal ? is_readable($File) : true; if ($FileAvailable) { // Close the database connection Gdn::database()->closeConnection(); // Determine if Path extension should be appended to Name $NameExtension = strtolower(pathinfo($Name, PATHINFO_EXTENSION)); $FileExtension = strtolower(pathinfo($File, PATHINFO_EXTENSION)); if ($NameExtension == '') { if ($Name == '') { $Name = pathinfo($File, PATHINFO_FILENAME) . '.' . $FileExtension; } elseif (!stringEndsWith($Name, '.' . $FileExtension)) { $Name .= '.' . $FileExtension; } } else { $Extension = $NameExtension; } $Name = rawurldecode($Name); // Figure out the MIME type $MimeTypes = array("pdf" => "application/pdf", "txt" => "text/plain", "html" => "text/html", "htm" => "text/html", "exe" => "application/octet-stream", "zip" => "application/zip", "doc" => "application/msword", "xls" => "application/vnd.ms-excel", "ppt" => "application/vnd.ms-powerpoint", "gif" => "image/gif", "png" => "image/png", "jpeg" => "image/jpg", "jpg" => "image/jpg", "php" => "text/plain", "ico" => "image/vnd.microsoft.icon"); if ($MimeType == '') { if (array_key_exists($FileExtension, $MimeTypes)) { $MimeType = $MimeTypes[$FileExtension]; } else { $MimeType = 'application/force-download'; } } @ob_end_clean(); // required for IE, otherwise Content-Disposition may be ignored if (ini_get('zlib.output_compression')) { ini_set('zlib.output_compression', 'Off'); } if ($ServeMode == 'inline') { safeHeader('Content-Disposition: inline; filename="' . $Name . '"'); } else { safeHeader('Content-Disposition: attachment; filename="' . $Name . '"'); } safeHeader('Content-Type: ' . $MimeType); safeHeader("Content-Transfer-Encoding: binary"); safeHeader('Accept-Ranges: bytes'); safeHeader("Cache-control: private"); safeHeader('Pragma: private'); safeHeader("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); readfile($File); exit; } else { die('not readable'); } }
/** * Import a table from a CSV using SQL insert statements. * * @param string $Tablename The name of the table to import to. * @param string $Path The path to the CSV. * @param bool $skipHeader Whether the CSV contains a header row. * @param int $chunk The number of records to chunk the imports to. * @return bool */ public function loadTableInsert($Tablename, $Path, $skipHeader = true, $chunk = 100) { // Get the column count of the table. $St = Gdn::structure(); $St->get(self::TABLE_PREFIX . $Tablename); $ColumnCount = count($St->Columns()); $St->reset(); ini_set('auto_detect_line_endings', true); $fp = fopen($Path, 'rb'); // Figure out the current position. $fPosition = val('CurrentLoadPosition', $this->Data, 0); if ($fPosition == 0 && $skipHeader) { // Skip the header row. $Row = self::FGetCSV2($fp); } if ($fPosition == 0) { $Px = Gdn::database()->DatabasePrefix . self::TABLE_PREFIX; Gdn::database()->query("truncate table {$Px}{$Tablename}"); } else { fseek($fp, $fPosition); } $PDO = Gdn::database()->connection(); $PxTablename = Gdn::database()->DatabasePrefix . self::TABLE_PREFIX . $Tablename; $Inserts = ''; $Count = 0; while ($Row = self::FGetCSV2($fp)) { ++$Count; $Row = array_map('trim', $Row); // Quote the values in the row. $Row = array_map(array($PDO, 'quote'), $Row); // Add any extra columns to the row. while (count($Row) < $ColumnCount) { $Row[] = 'null'; } // Add the insert values to the sql. if (strlen($Inserts) > 0) { $Inserts .= ','; } $Inserts .= '(' . implode(',', $Row) . ')'; if ($Count >= $chunk) { // Insert in chunks. $Sql = "insert {$PxTablename} values {$Inserts}"; $this->Database->query($Sql); $Count = 0; $Inserts = ''; // Check for a timeout. if ($this->Timer->ElapsedTime() > $this->MaxStepTime) { // The step's taken too long. Save the file position. $Pos = ftell($fp); $this->Data['CurrentLoadPosition'] = $Pos; $Filesize = filesize($Path); if ($Filesize > 0) { $PercentComplete = $Pos / filesize($Path); $this->Data['CurrentStepMessage'] = $Tablename . ' (' . round($PercentComplete * 100.0) . '%)'; } fclose($fp); return 0; } } } fclose($fp); if (strlen($Inserts) > 0) { $Sql = "insert {$PxTablename} values {$Inserts}"; $this->query($Sql); } return $Count; }
/** * A custom error handler that displays much more, very useful information when * errors are encountered in Garden. * * @param Exception $Exception The exception that was thrown. */ function Gdn_ExceptionHandler($Exception) { try { $ErrorNumber = $Exception->getCode(); $Message = $Exception->getMessage(); $File = $Exception->getFile(); $Line = $Exception->getLine(); if (method_exists($Exception, 'getContext')) { $Arguments = $Exception->getContext(); } else { $Arguments = ''; } $Backtrace = $Exception->getTrace(); // Clean the output buffer in case an error was encountered in-page. @ob_end_clean(); // prevent headers already sent error if (!headers_sent()) { if ($ErrorNumber >= 100 && $ErrorNumber < 600) { $Code = $ErrorNumber; } else { $Code = 500; } if (class_exists('Gdn_Controller', false)) { $msg = Gdn_Controller::getStatusMessage($Code); } else { $msg = 'Error'; } safeHeader("HTTP/1.0 {$Code} {$msg}", true, $ErrorNumber); safeHeader('Content-Type: text/html; charset=utf-8'); } $SenderMessage = $Message; $SenderObject = 'PHP'; $SenderMethod = 'Gdn_ErrorHandler'; $SenderCode = false; $SenderTrace = $Backtrace; $MessageInfo = explode('|', $Message); $MessageCount = count($MessageInfo); if ($MessageCount == 4) { list($SenderMessage, $SenderObject, $SenderMethod, $SenderCode) = $MessageInfo; } elseif ($MessageCount == 3) { list($SenderMessage, $SenderObject, $SenderMethod) = $MessageInfo; } elseif (function_exists('GetValueR')) { $IsError = GetValueR('0.function', $SenderTrace) == 'Gdn_ErrorHandler'; // not exception $N = $IsError ? '1' : '0'; $SenderMethod = GetValueR($N . '.function', $SenderTrace, $SenderMethod); $SenderObject = GetValueR($N . '.class', $SenderTrace, $SenderObject); } $SenderMessage = htmlspecialchars($SenderMessage); $Master = false; // The parsed master view $CssPath = false; // The web-path to the css file $ErrorLines = false; // The lines near the error's line # $DeliveryType = defined('DELIVERY_TYPE_ALL') ? DELIVERY_TYPE_ALL : 'ALL'; if (array_key_exists('DeliveryType', $_POST)) { $DeliveryType = $_POST['DeliveryType']; } elseif (array_key_exists('DeliveryType', $_GET)) { $DeliveryType = $_GET['DeliveryType']; } if (function_exists('debug') && debug()) { $Debug = true; } else { $Debug = false; } // Make sure all of the required custom functions and variables are defined. $PanicError = false; // Should we just dump a message and forget about the master view? if (!defined('DS')) { $PanicError = true; } if (!defined('PATH_ROOT')) { $PanicError = true; } if (!defined('APPLICATION')) { define('APPLICATION', 'Garden'); } if (!defined('APPLICATION_VERSION')) { define('APPLICATION_VERSION', 'Unknown'); } $WebRoot = ''; // Try and rollback a database transaction. if (class_exists('Gdn', false)) { $Database = Gdn::database(); if (is_object($Database)) { $Database->rollbackTransaction(); } } if ($PanicError === false) { // See if we can get the file that caused the error if (is_string($File) && is_numeric($ErrorNumber)) { $ErrorLines = @file($File); } // If this error was encountered during an ajax request, don't bother gettting the css or theme files if ($DeliveryType == DELIVERY_TYPE_ALL) { $CssPaths = array(); // Potential places where the css can be found in the filesystem. $MasterViewPaths = array(); $MasterViewName = 'error.master.php'; $MasterViewCss = 'error.css'; if ($Debug) { $MasterViewName = 'deverror.master.php'; } if (class_exists('Gdn', false)) { $CurrentTheme = ''; // The currently selected theme $CurrentTheme = C('Garden.Theme', ''); $MasterViewName = C('Garden.Errors.MasterView', $MasterViewName); $MasterViewCss = substr($MasterViewName, 0, strpos($MasterViewName, '.')); if ($MasterViewCss == '') { $MasterViewCss = 'error'; } $MasterViewCss .= '.css'; if ($CurrentTheme != '') { // Look for CSS in the theme folder: $CssPaths[] = PATH_THEMES . DS . $CurrentTheme . DS . 'design' . DS . $MasterViewCss; // Look for Master View in the theme folder: $MasterViewPaths[] = PATH_THEMES . DS . $CurrentTheme . DS . 'views' . DS . $MasterViewName; } } // Look for CSS in the dashboard design folder. $CssPaths[] = PATH_APPLICATIONS . DS . 'dashboard' . DS . 'design' . DS . $MasterViewCss; // Look for Master View in the dashboard view folder. $MasterViewPaths[] = PATH_APPLICATIONS . DS . 'dashboard' . DS . 'views' . DS . $MasterViewName; $CssPath = false; $Count = count($CssPaths); for ($i = 0; $i < $Count; ++$i) { if (file_exists($CssPaths[$i])) { $CssPath = $CssPaths[$i]; break; } } if ($CssPath !== false) { $CssPath = str_replace(array(PATH_ROOT, DS), array('', '/'), $CssPath); $CssPath = ($WebRoot == '' ? '' : '/' . $WebRoot) . $CssPath; } $MasterViewPath = false; $Count = count($MasterViewPaths); for ($i = 0; $i < $Count; ++$i) { if (file_exists($MasterViewPaths[$i])) { $MasterViewPath = $MasterViewPaths[$i]; break; } } if ($MasterViewPath !== false) { include $MasterViewPath; $Master = true; } } } if ($DeliveryType != DELIVERY_TYPE_ALL) { if (!$Debug) { echo '<b class="Bonk">Whoops! There was an error.</b>'; echo '<div class="BonkError Hidden">'; } // This is an ajax request, so dump an error that is more eye-friendly in the debugger echo '<h1>FATAL ERROR IN: ', $SenderObject, '.', $SenderMethod, "();</h1>\n<pre class=\"AjaxError\">\"" . $SenderMessage . "\"\n"; if ($SenderCode != '') { echo htmlspecialchars($SenderCode, ENT_COMPAT, C('Garden.Charset', 'UTF-8')) . "\n"; } if (is_array($ErrorLines) && $Line > -1) { echo "\nLOCATION: ", $File, "\n"; } $LineCount = count($ErrorLines); $Padding = strlen($Line + 5); for ($i = 0; $i < $LineCount; ++$i) { if ($i > $Line - 6 && $i < $Line + 4) { if ($i == $Line - 1) { echo '>>'; } echo '> ' . str_pad($i + 1, $Padding, " ", STR_PAD_LEFT), ': ', str_replace(array("\n", "\r"), array('', ''), htmlspecialchars($ErrorLines[$i])), "\n"; } } if (is_array($Backtrace)) { echo "\nBACKTRACE:\n"; $BacktraceCount = count($Backtrace); for ($i = 0; $i < $BacktraceCount; ++$i) { if (array_key_exists('file', $Backtrace[$i])) { $File = $Backtrace[$i]['file'] . ' ' . $Backtrace[$i]['line']; } echo '[' . $File . ']', ' ', array_key_exists('class', $Backtrace[$i]) ? $Backtrace[$i]['class'] : 'PHP', array_key_exists('type', $Backtrace[$i]) ? $Backtrace[$i]['type'] : '::', $Backtrace[$i]['function'], '();', "\n"; } } echo '</pre>'; if (!$Debug) { echo '</div>'; } } else { // If the master view wasn't found, assume a panic state and dump the error. if ($Master === false) { echo '<!DOCTYPE html> <html> <head> <title>Fatal Error</title> </head> <body> <h1>Fatal Error in ', $SenderObject, '.', $SenderMethod, '();</h1> <h2>', $SenderMessage, "</h2>\n"; if ($SenderCode != '') { echo '<code>', htmlentities($SenderCode, ENT_COMPAT, 'UTF-8'), "</code>\n"; } if (is_array($ErrorLines) && $Line > -1) { echo '<h3><strong>The error occurred on or near:</strong> ', $File, '</h3> <pre>'; $LineCount = count($ErrorLines); $Padding = strlen($Line + 4); for ($i = 0; $i < $LineCount; ++$i) { if ($i > $Line - 6 && $i < $Line + 4) { echo str_pad($i, $Padding, " ", STR_PAD_LEFT), ': ', htmlentities($ErrorLines[$i], ENT_COMPAT, 'UTF-8'); } } echo "</pre>\n"; } echo '<h2>Need Help?</h2> <p>If you are a user of this website, you can report this message to a website administrator.</p> <p>If you are an administrator of this website, you can get help at the <a href="http://vanillaforums.org/discussions/" target="_blank">Vanilla Community Forums</a>.</p> <h2>Additional information for support personnel:</h2> <ul> <li><strong>Application:</strong> ', APPLICATION, '</li> <li><strong>Application Version:</strong> ', APPLICATION_VERSION, '</li> <li><strong>PHP Version:</strong> ', PHP_VERSION, '</li> <li><strong>Operating System:</strong> ', PHP_OS, "</li>\n"; if (array_key_exists('SERVER_SOFTWARE', $_SERVER)) { echo '<li><strong>Server Software:</strong> ', $_SERVER['SERVER_SOFTWARE'], "</li>\n"; } if (array_key_exists('HTTP_REFERER', $_SERVER)) { echo '<li><strong>Referer:</strong> ', $_SERVER['HTTP_REFERER'], "</li>\n"; } if (array_key_exists('HTTP_USER_AGENT', $_SERVER)) { echo '<li><strong>User Agent:</strong> ', $_SERVER['HTTP_USER_AGENT'], "</li>\n"; } if (array_key_exists('REQUEST_URI', $_SERVER)) { echo '<li><strong>Request Uri:</strong> ', $_SERVER['REQUEST_URI'], "</li>\n"; } echo '</ul> </body> </html>'; } } // Attempt to log an error message no matter what. LogException($Exception); } catch (Exception $e) { print get_class($e) . " thrown within the exception handler.<br/>Message: " . $e->getMessage() . " in " . $e->getFile() . " on line " . $e->getLine(); exit; } }
/** * Automatically executed when application is enabled. * * @since 2.0.0 * @package Vanilla */ public function setup() { $Database = Gdn::database(); $Config = Gdn::factory(Gdn::AliasConfig); $Drop = false; // Call structure.php to update database $Validation = new Gdn_Validation(); // Needed by structure.php to validate permission names include PATH_APPLICATIONS . DS . 'vanilla' . DS . 'settings' . DS . 'structure.php'; saveToConfig('Routes.DefaultController', 'discussions'); }
/** * Increments overall pageview view count. * * @since 2.1a * @access public */ public function addView($ViewType = 'normal') { // Add a pageview entry. $TimeSlot = date('Ymd'); $Px = Gdn::database()->DatabasePrefix; $Views = 1; $EmbedViews = 0; try { if (C('Garden.Analytics.Views.Denormalize', false) && Gdn::cache()->activeEnabled() && Gdn::cache()->type() != Gdn_Cache::CACHE_TYPE_NULL) { $CacheKey = "QueryCache.Analytics.CountViews"; // Increment. If not success, create key. $Incremented = Gdn::cache()->increment($CacheKey); if ($Incremented === Gdn_Cache::CACHEOP_FAILURE) { Gdn::cache()->store($CacheKey, 1); } // Get current cache value $Views = Gdn::cache()->get($CacheKey); if ($ViewType == 'embed') { $EmbedCacheKey = "QueryCache.Analytics.CountEmbedViews"; // Increment. If not success, create key. $EmbedIncremented = Gdn::cache()->increment($EmbedCacheKey); if ($EmbedIncremented === Gdn_Cache::CACHEOP_FAILURE) { Gdn::cache()->store($EmbedCacheKey, 1); } // Get current cache value $EmbedViews = Gdn::cache()->get($EmbedCacheKey); } // Every X views, writeback to AnalyticsLocal $DenormalizeWriteback = C('Garden.Analytics.Views.DenormalizeWriteback', 10); if ($Views % $DenormalizeWriteback == 0) { Gdn::controller()->setData('WritebackViews', $Views); Gdn::controller()->setData('WritebackEmbed', $EmbedViews); Gdn::database()->query("insert into {$Px}AnalyticsLocal (TimeSlot, Views, EmbedViews) values (:TimeSlot, {$Views}, {$EmbedViews})\n on duplicate key update\n Views = COALESCE(Views, 0)+{$Views},\n EmbedViews = COALESCE(EmbedViews, 0)+{$EmbedViews}", array(':TimeSlot' => $TimeSlot)); // ... and get rid of those views from the keys if ($Views) { Gdn::cache()->decrement($CacheKey, $Views); } if ($EmbedViews) { Gdn::cache()->decrement($EmbedCacheKey, $EmbedViews); } } } else { $ExtraViews = 1; $ExtraEmbedViews = $ViewType == 'embed' ? 1 : 0; Gdn::database()->query("insert into {$Px}AnalyticsLocal (TimeSlot, Views, EmbedViews) values (:TimeSlot, {$ExtraViews}, {$ExtraEmbedViews})\n on duplicate key update\n Views = COALESCE(Views, 0)+{$ExtraViews},\n EmbedViews = COALESCE(EmbedViews, 0)+{$ExtraEmbedViews}", array(':TimeSlot' => $TimeSlot)); } } catch (Exception $Ex) { if (Gdn::session()->checkPermission('Garden.Settings.Manage')) { throw $Ex; } } }
/** * Looks for a Last-Modified header from the browser and compares it to the * supplied date. If the Last-Modified date is after the supplied date, the * controller will send a "304 Not Modified" response code to the web * browser and stop all execution. Otherwise it sets the Last-Modified * header for this page and continues processing. * * @param string $LastModifiedDate A unix timestamp representing the date that the current page was last * modified. */ public function setLastModified($LastModifiedDate) { $GMD = gmdate('D, d M Y H:i:s', $LastModifiedDate) . ' GMT'; $this->setHeader('Etag', '"' . $GMD . '"'); $this->setHeader('Last-Modified', $GMD); $IncomingHeaders = getallheaders(); if (isset($IncomingHeaders['If-Modified-Since']) && isset($IncomingHeaders['If-None-Match'])) { $IfNoneMatch = $IncomingHeaders['If-None-Match']; $IfModifiedSince = $IncomingHeaders['If-Modified-Since']; if ($GMD == $IfNoneMatch && $IfModifiedSince == $GMD) { $Database = Gdn::database(); if (!is_null($Database)) { $Database->closeConnection(); } $this->setHeader('Content-Length', '0'); $this->sendHeaders(); safeHeader('HTTP/1.1 304 Not Modified'); exit("\n\n"); // Send two linefeeds so that the client knows the response is complete } } }
/** * * * @throws Exception */ public function recalculate() { if ($DiscussionIDs = val('Discussion', $this->_RecalcIDs)) { $In = implode(',', array_keys($DiscussionIDs)); if (!empty($In)) { $Px = Gdn::database()->DatabasePrefix; $Sql = "update {$Px}Discussion d set d.CountComments = (select coalesce(count(c.CommentID), 0) + 1 from {$Px}Comment c where c.DiscussionID = d.DiscussionID) where d.DiscussionID in ({$In})"; Gdn::database()->query($Sql); $this->_RecalcIDs['Discussion'] = array(); } } if ($UserIDsComment = val('UserComment', $this->_RecalcIDs)) { $counts = $this->arrayFlipAndCombine($UserIDsComment); foreach ($counts as $key => $value) { Gdn::sql()->update('User')->set('CountComments', 'coalesce(CountComments, 0) + ' . $key, false, false)->where('UserID', $value)->put(); } $this->_RecalcIDs['UserComment'] = array(); } if ($UserIDsDiscussion = val('UserDiscussion', $this->_RecalcIDs)) { $counts = $this->arrayFlipAndCombine($UserIDsDiscussion); foreach ($counts as $key => $value) { Gdn::sql()->update('User')->set('CountDiscussions', 'coalesce(CountDiscussions, 0) + ' . $key, false, false)->where('UserID', $value)->put(); } $this->_RecalcIDs['UserDiscussion'] = array(); } }
/** * * * @param int $UserID * @param array $Meta * @param string $Prefix */ public static function setMeta($UserID, $Meta, $Prefix = '') { $Deletes = []; $Px = Gdn::database()->DatabasePrefix; $Sql = "insert {$Px}UserMeta (UserID, Name, Value) values(:UserID, :Name, :Value) on duplicate key update Value = :Value1"; foreach ($Meta as $Name => $Value) { $Name = $Prefix . $Name; if ($Value === null || $Value == '') { $Deletes[] = $Name; } else { Gdn::database()->query($Sql, [':UserID' => $UserID, ':Name' => $Name, ':Value' => $Value, ':Value1' => $Value]); } } if (count($Deletes)) { Gdn::sql()->whereIn('Name', $Deletes)->where('UserID', $UserID)->delete('UserMeta'); } }
/** * * * @param string $Key Cache key. * @param array $Options * @return mixed */ protected function fallback($Key, $Options) { $Fallback = val(Gdn_Cache::FEATURE_FALLBACK, $Options, null); if (is_null($Fallback)) { return Gdn_Cache::CACHEOP_FAILURE; } $FallbackType = array_shift($Fallback); switch ($FallbackType) { case 'query': $QueryFallbackField = array_shift($Fallback); $QueryFallbackCode = array_shift($Fallback); $FallbackResult = Gdn::database()->query($QueryFallbackCode); if ($FallbackResult->numRows()) { if (!is_null($QueryFallbackField)) { $FallbackResult = val($QueryFallbackField, $FallbackResult->firstRow(DATASET_TYPE_ARRAY)); } else { $FallbackResult = $FallbackResult->resultArray(); } } break; case 'callback': $CallbackFallbackMethod = array_shift($Fallback); $CallbackFallbackArgs = $Fallback; $FallbackResult = call_user_func_array($CallbackFallbackMethod, $CallbackFallbackArgs); break; } Gdn::cache()->store($Key, $FallbackResult); return $FallbackResult; }
/** * Whether or not we are past the user threshold. */ protected function pastUserThreshold() { $px = Gdn::database()->DatabasePrefix; $countEstimate = Gdn::database()->query("show table status like '{$px}User'")->value('Rows', 0); return $countEstimate > $this->UserThreshold; }
/** * If looking at the root node, make sure it exists and that the * nested set columns exist in the table. * * @since 2.0.15 * @access public */ public function applyUpdates() { if (!c('Vanilla.NestedCategoriesUpdate')) { // Add new columns $Construct = Gdn::database()->Structure(); $Construct->table('Category')->column('TreeLeft', 'int', true)->column('TreeRight', 'int', true)->column('Depth', 'int', true)->column('CountComments', 'int', '0')->column('LastCommentID', 'int', true)->set(0, 0); // Insert the root node if ($this->SQL->getWhere('Category', array('CategoryID' => -1))->numRows() == 0) { $this->SQL->insert('Category', array('CategoryID' => -1, 'TreeLeft' => 1, 'TreeRight' => 4, 'Depth' => 0, 'InsertUserID' => 1, 'UpdateUserID' => 1, 'DateInserted' => Gdn_Format::toDateTime(), 'DateUpdated' => Gdn_Format::toDateTime(), 'Name' => t('Root Category Name', 'Root'), 'UrlCode' => '', 'Description' => t('Root Category Description', 'Root of category tree. Users should never see this.'))); } // Build up the TreeLeft & TreeRight values. $this->rebuildTree(); saveToConfig('Vanilla.NestedCategoriesUpdate', 1); } }
/** * Run the structure for all addons. * * The structure runs the addons in priority order so that higher priority addons override lower priority ones. * * @param bool $captureOnly Run the structure or just capture the SQL changes. * @throws Exception Throws an exception if in debug mode and something goes wrong. */ public function runStructure($captureOnly = false) { $addons = array_reverse(Gdn::addonManager()->getEnabled()); // These variables are required for included structure files. $Database = Gdn::database(); $SQL = $this->SQL; $SQL->CaptureModifications = $captureOnly; $Structure = Gdn::structure(); $Structure->CaptureOnly = $captureOnly; /* @var Addon $addon */ foreach ($addons as $addon) { // Look for a structure file. if ($structure = $addon->getSpecial('structure')) { Logger::event('addon_structure', Logger::INFO, "Executing structure for {addonKey}.", ['addonKey' => $addon->getKey(), 'structureType' => 'file']); try { include $addon->path($structure); } catch (\Exception $ex) { if (debug()) { throw $ex; } } } // Look for a structure method on the plugin. if ($addon->getPluginClass()) { $plugin = Gdn::pluginManager()->getPluginInstance($addon->getPluginClass(), Gdn_PluginManager::ACCESS_CLASSNAME); if (is_object($plugin) && method_exists($plugin, 'structure')) { Logger::event('addon_structure', Logger::INFO, "Executing structure for {addonKey}.", ['addonKey' => $addon->getKey(), 'structureType' => 'method']); try { call_user_func([$plugin, 'structure']); } catch (\Exception $ex) { if (debug()) { throw $ex; } } } } // Register permissions. $permissions = $addon->getInfoValue('registerPermissions'); if (!empty($permissions)) { Logger::event('addon_permissions', Logger::INFO, "Defining permissions for {addonKey}.", ['addonKey' => $addon->getKey(), 'permissions' => $permissions]); Gdn::permissionModel()->define($permissions); } } $this->fireEvent('AfterStructure'); if ($captureOnly && property_exists($Structure->Database, 'CapturedSql')) { return $Structure->Database->CapturedSql; } return []; }
/** * Get the number of comments inserted since the given timestamp. * * @since 1.0 * @access public */ public function getCommentCountSince($DiscussionID, $DateAllViewed) { // Only for members if (!Gdn::session()->isValid()) { return; } // Validate DiscussionID $DiscussionID = (int) $DiscussionID; if (!$DiscussionID) { throw new Exception('A valid DiscussionID is required in GetCommentCountSince.'); } // Get new comment count return Gdn::database()->sql()->from('Comment c')->where('DiscussionID', $DiscussionID)->where('DateInserted >', Gdn_Format::toDateTime($DateAllViewed))->getCount(); }
// Message Table $Construct->table('Message')->primaryKey('MessageID')->column('Content', 'text')->column('Format', 'varchar(20)', true)->column('AllowDismiss', 'tinyint(1)', '1')->column('Enabled', 'tinyint(1)', '1')->column('Application', 'varchar(255)', true)->column('Controller', 'varchar(255)', true)->column('Method', 'varchar(255)', true)->column('CategoryID', 'int', true)->column('IncludeSubcategories', 'tinyint', '0')->column('AssetTarget', 'varchar(20)', true)->column('CssClass', 'varchar(20)', true)->column('Sort', 'int', true)->set($Explicit, $Drop); $Prefix = $SQL->Database->DatabasePrefix; if ($PhotoIDExists && !$PhotoExists) { $Construct->query("update {$Prefix}User u\n join {$Prefix}Photo p\n on u.PhotoID = p.PhotoID\n set u.Photo = p.Name"); } if ($PhotoIDExists) { $Construct->table('User')->dropColumn('PhotoID'); } $Construct->table('Tag'); $FullNameColumnExists = $Construct->columnExists('FullName'); $TagCategoryColumnExists = $Construct->columnExists('CategoryID'); // This is a fix for erroneous unique constraint. if ($Construct->tableExists('Tag') && $TagCategoryColumnExists) { $Db = Gdn::database(); $Px = Gdn::database()->DatabasePrefix; $DupTags = Gdn::sql()->select('Name, CategoryID')->select('TagID', 'min', 'TagID')->select('TagID', 'count', 'CountTags')->from('Tag')->groupBy('Name')->groupBy('CategoryID')->having('CountTags >', 1)->get()->resultArray(); foreach ($DupTags as $Row) { $Name = $Row['Name']; $CategoryID = $Row['CategoryID']; $TagID = $Row['TagID']; // Get the tags that need to be deleted. $DeleteTags = Gdn::sql()->getWhere('Tag', array('Name' => $Name, 'CategoryID' => $CategoryID, 'TagID <> ' => $TagID))->resultArray(); foreach ($DeleteTags as $DRow) { // Update all of the discussions to the new tag. Gdn::sql()->options('Ignore', true)->put('TagDiscussion', array('TagID' => $TagID), array('TagID' => $DRow['TagID'])); // Delete the tag. Gdn::sql()->delete('Tag', array('TagID' => $DRow['TagID'])); } } }
/** * Apply the specified RoleID to all users without a valid role * * @param $RoleID * @return bool|Gdn_DataSet|string * @throws Exception */ public function fixUserRole($RoleID) { $PDO = Gdn::database()->connection(); $InsertQuery = "\n insert into :_UserRole\n\n select u.UserID, " . $PDO->quote($RoleID) . " as RoleID\n from :_User u\n left join :_UserRole ur on u.UserID = ur.UserID\n left join :_Role r on ur.RoleID = r.RoleID\n where r.Name is null"; $InsertQuery = str_replace(':_', Gdn::database()->DatabasePrefix, $InsertQuery); return $this->SQL->query($InsertQuery); }