mirror of
https://github.com/Mibew/mibew.git
synced 2025-02-07 08:14:42 +03:00
Merge branch 'auto_update'
This commit is contained in:
commit
b340206d3a
@ -11,7 +11,7 @@ This repository contains the core of Mibew Messenger application.
|
|||||||
## Server requirements
|
## Server requirements
|
||||||
|
|
||||||
1. A webserver or web hosting account running on any major Operating System
|
1. A webserver or web hosting account running on any major Operating System
|
||||||
2. PHP (5.3.3 and above) with PDO, pdo_mysql and gd extensions
|
2. PHP (5.3.3 and above) with PDO, pdo_mysql, cURL and gd extensions
|
||||||
3. MySQL 5.0 and above
|
3. MySQL 5.0 and above
|
||||||
|
|
||||||
## Build from sources
|
## Build from sources
|
||||||
|
@ -6,7 +6,7 @@ REQUIREMENTS
|
|||||||
* Apache web server 1.3.34 or above with the ability to use local .htaccess
|
* Apache web server 1.3.34 or above with the ability to use local .htaccess
|
||||||
files (mod_rewrite module is optional, but recommended)
|
files (mod_rewrite module is optional, but recommended)
|
||||||
* MySQL database 5.0 or above
|
* MySQL database 5.0 or above
|
||||||
* PHP 5.3.3 or above with PDO, pdo_mysql and gd extensions
|
* PHP 5.3.3 or above with PDO, pdo_mysql, cURL and gd extensions
|
||||||
|
|
||||||
INSTALLATION
|
INSTALLATION
|
||||||
|
|
||||||
|
@ -316,3 +316,19 @@ plugin:
|
|||||||
enabled: "tinyint NOT NULL DEFAULT 0"
|
enabled: "tinyint NOT NULL DEFAULT 0"
|
||||||
unique_keys:
|
unique_keys:
|
||||||
name: [name]
|
name: [name]
|
||||||
|
|
||||||
|
# Contains info about all available updates
|
||||||
|
availableupdate:
|
||||||
|
fields:
|
||||||
|
# Artificial ID
|
||||||
|
id: "INT NOT NULL auto_increment PRIMARY KEY"
|
||||||
|
# Can be either "core" or fully qualified plugin's name
|
||||||
|
target: "varchar(255) NOT NULL"
|
||||||
|
# The latest available version of the plugin
|
||||||
|
version: "varchar(255) NOT NULL"
|
||||||
|
# A URL where the new version can be downloaded
|
||||||
|
url: "text"
|
||||||
|
# Description of the update
|
||||||
|
description: "text"
|
||||||
|
unique_keys:
|
||||||
|
target: [target]
|
||||||
|
@ -759,6 +759,13 @@ update_run:
|
|||||||
_access_check: Mibew\AccessControl\Check\PermissionsCheck
|
_access_check: Mibew\AccessControl\Check\PermissionsCheck
|
||||||
_access_permissions: [CAN_ADMINISTRATE]
|
_access_permissions: [CAN_ADMINISTRATE]
|
||||||
|
|
||||||
|
update_check:
|
||||||
|
path: /update/check
|
||||||
|
defaults:
|
||||||
|
_controller: Mibew\Controller\UpdateController::checkUpdatesAction
|
||||||
|
_access_check: Mibew\AccessControl\Check\PermissionsCheck
|
||||||
|
_access_permissions: [CAN_ADMINISTRATE]
|
||||||
|
|
||||||
## Users (visitors avaiting page)
|
## Users (visitors avaiting page)
|
||||||
users:
|
users:
|
||||||
path: /operator/users
|
path: /operator/users
|
||||||
|
@ -1,40 +0,0 @@
|
|||||||
/*!
|
|
||||||
* This file is a part of Mibew Messenger.
|
|
||||||
*
|
|
||||||
* Copyright 2005-2015 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
(function (Mibew, $) {
|
|
||||||
Mibew.updateVersion = function(data) {
|
|
||||||
if (!data.core || !data.core.stable) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$(document).ready(function() {
|
|
||||||
var currentVersion = $("#current-version").html(),
|
|
||||||
core = data.core.stable;
|
|
||||||
|
|
||||||
if (currentVersion != core.version) {
|
|
||||||
if (currentVersion < core.version) {
|
|
||||||
$("#current-version").css("color", "red");
|
|
||||||
}
|
|
||||||
$("#latest-version").html(core.version + ", Download <a href=\"" + core.download + "\">" + core.title + "</a>");
|
|
||||||
} else {
|
|
||||||
$("#current-version").css("color", "green");
|
|
||||||
$("#latest-version").html(core.version);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})(Mibew, jQuery);
|
|
@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
namespace Mibew\Controller;
|
namespace Mibew\Controller;
|
||||||
|
|
||||||
use Mibew\Asset\AssetManagerInterface;
|
use Mibew\Maintenance\AvailableUpdate;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -43,16 +43,11 @@ class AboutController extends AbstractController
|
|||||||
'version' => MIBEW_VERSION,
|
'version' => MIBEW_VERSION,
|
||||||
'title' => getlocal('About'),
|
'title' => getlocal('About'),
|
||||||
'menuid' => 'about',
|
'menuid' => 'about',
|
||||||
|
'availableUpdates' => $this->getAvailableUpdates(),
|
||||||
),
|
),
|
||||||
prepare_menu($this->getOperator())
|
prepare_menu($this->getOperator())
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->getAssetManager()->attachJs('js/compiled/about.js');
|
|
||||||
$this->getAssetManager()->attachJs(
|
|
||||||
'https://mibew.org/api/updates',
|
|
||||||
AssetManagerInterface::ABSOLUTE_URL
|
|
||||||
);
|
|
||||||
|
|
||||||
return $this->render('about', $page);
|
return $this->render('about', $page);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,7 +63,7 @@ class AboutController extends AbstractController
|
|||||||
*/
|
*/
|
||||||
protected function getExtensionsInfo()
|
protected function getExtensionsInfo()
|
||||||
{
|
{
|
||||||
$required_extensions = array('PDO', 'pdo_mysql', 'gd');
|
$required_extensions = array('PDO', 'pdo_mysql', 'gd', 'curl');
|
||||||
$info = array();
|
$info = array();
|
||||||
foreach ($required_extensions as $ext) {
|
foreach ($required_extensions as $ext) {
|
||||||
if (!extension_loaded($ext)) {
|
if (!extension_loaded($ext)) {
|
||||||
@ -86,4 +81,39 @@ class AboutController extends AbstractController
|
|||||||
|
|
||||||
return $info;
|
return $info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds list of available updates to display in the template.
|
||||||
|
*
|
||||||
|
* @return array List of updates data. Each item of the list is associative
|
||||||
|
* array with the following keys:
|
||||||
|
* - "title": string, title of the update.
|
||||||
|
* - "version": string, the latest available version.
|
||||||
|
* - "url": string, URL of the page the updated version can be downloaded
|
||||||
|
* from.
|
||||||
|
* - "description": string, description of the update.
|
||||||
|
*/
|
||||||
|
protected function getAvailableUpdates()
|
||||||
|
{
|
||||||
|
$updates = AvailableUpdate::all();
|
||||||
|
if (!$updates) {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = array();
|
||||||
|
foreach ($updates as $update) {
|
||||||
|
$title = ($update->target == 'core')
|
||||||
|
? 'Mibew'
|
||||||
|
: getlocal('{0} plugin', array($update->target));
|
||||||
|
|
||||||
|
$data[] = array(
|
||||||
|
'title' => $title,
|
||||||
|
'version' => $update->version,
|
||||||
|
'url' => $update->url,
|
||||||
|
'description' => $update->description,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -111,6 +111,7 @@ class FeaturesController extends AbstractController
|
|||||||
'showonlineoperators',
|
'showonlineoperators',
|
||||||
'enablecaptcha',
|
'enablecaptcha',
|
||||||
'trackoperators',
|
'trackoperators',
|
||||||
|
'autocheckupdates',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,9 @@
|
|||||||
|
|
||||||
namespace Mibew\Controller;
|
namespace Mibew\Controller;
|
||||||
|
|
||||||
|
use Mibew\Maintenance\UpdateChecker;
|
||||||
use Mibew\Maintenance\Updater;
|
use Mibew\Maintenance\Updater;
|
||||||
|
use Mibew\Settings;
|
||||||
use Mibew\Style\PageStyle;
|
use Mibew\Style\PageStyle;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
|
||||||
@ -33,6 +35,11 @@ class UpdateController extends AbstractController
|
|||||||
*/
|
*/
|
||||||
protected $updater = null;
|
protected $updater = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var UpdateChecker|null
|
||||||
|
*/
|
||||||
|
protected $updateChecker = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Renders update intro page.
|
* Renders update intro page.
|
||||||
*
|
*
|
||||||
@ -74,6 +81,26 @@ class UpdateController extends AbstractController
|
|||||||
return $this->render('update_progress', $parameters);
|
return $this->render('update_progress', $parameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs the Update checker.
|
||||||
|
*
|
||||||
|
* @param Request $request Incoming request.
|
||||||
|
* @return Response|string Rendered page contents or Symfony's response
|
||||||
|
* object.
|
||||||
|
*/
|
||||||
|
public function checkUpdatesAction(Request $request)
|
||||||
|
{
|
||||||
|
$checker = $this->getUpdateChecker();
|
||||||
|
$success = $checker->run();
|
||||||
|
if (!$success) {
|
||||||
|
foreach ($checker->getErrors() as $error) {
|
||||||
|
trigger_error('Update checking failed: ' . $error, E_USER_WARNING);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->redirect($this->generateUrl('about'));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
@ -99,4 +126,22 @@ class UpdateController extends AbstractController
|
|||||||
|
|
||||||
return $this->updater;
|
return $this->updater;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an instance of Update Checker.
|
||||||
|
*
|
||||||
|
* @return UpdateChecker
|
||||||
|
*/
|
||||||
|
protected function getUpdateChecker()
|
||||||
|
{
|
||||||
|
if (is_null($this->updateChecker)) {
|
||||||
|
$this->updateChecker = new UpdateChecker();
|
||||||
|
$id = Settings::get('_instance_id');
|
||||||
|
if ($id) {
|
||||||
|
$this->updateChecker->setInstanceId($id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->updateChecker;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
253
src/mibew/libs/classes/Mibew/Maintenance/AvailableUpdate.php
Normal file
253
src/mibew/libs/classes/Mibew/Maintenance/AvailableUpdate.php
Normal file
@ -0,0 +1,253 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is a part of Mibew Messenger.
|
||||||
|
*
|
||||||
|
* Copyright 2005-2015 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Mibew\Maintenance;
|
||||||
|
|
||||||
|
use Mibew\Database;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a record about available update with all necessary info.
|
||||||
|
*/
|
||||||
|
class AvailableUpdate
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Unique (for the current Mibew instance) update ID.
|
||||||
|
*
|
||||||
|
* @type int
|
||||||
|
*/
|
||||||
|
public $id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* String representing update target.
|
||||||
|
*
|
||||||
|
* It can be equal to either "core" or fully qualified plugin's name.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The latest version the core/plugin can be updated to.
|
||||||
|
*
|
||||||
|
* @type string
|
||||||
|
*/
|
||||||
|
public $version;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The URL the update can be downloaded from.
|
||||||
|
*
|
||||||
|
* @type string
|
||||||
|
*/
|
||||||
|
public $url;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Arbitrary description of the update.
|
||||||
|
*
|
||||||
|
* @type string
|
||||||
|
*/
|
||||||
|
public $description;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads update by its ID.
|
||||||
|
*
|
||||||
|
* @param int $id ID of the update to load
|
||||||
|
* @return boolean|AvailableUpdate Returns an AvailableUpdate instance or
|
||||||
|
* boolean false on failure.
|
||||||
|
*/
|
||||||
|
public static function load($id)
|
||||||
|
{
|
||||||
|
// Check $id
|
||||||
|
if (empty($id)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load update's info
|
||||||
|
$info = Database::getInstance()->query(
|
||||||
|
"SELECT * FROM {availableupdate} WHERE id = :id",
|
||||||
|
array(':id' => $id),
|
||||||
|
array('return_rows' => Database::RETURN_ONE_ROW)
|
||||||
|
);
|
||||||
|
|
||||||
|
// There is no update with such id in database
|
||||||
|
if (!$info) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create and populate update object
|
||||||
|
$update = new self();
|
||||||
|
$update->populateFromDbFields($info);
|
||||||
|
|
||||||
|
return $update;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads update by its target.
|
||||||
|
*
|
||||||
|
* @param string $target Target of the update to load.
|
||||||
|
* @return boolean|AvailableUpdate Returns an AvailableUpdate instance or
|
||||||
|
* boolean false on failure.
|
||||||
|
*/
|
||||||
|
public static function loadByTarget($target)
|
||||||
|
{
|
||||||
|
// Check the target
|
||||||
|
if (empty($target)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load update info
|
||||||
|
$info = Database::getInstance()->query(
|
||||||
|
"SELECT * FROM {availableupdate} WHERE target = :target",
|
||||||
|
array(':target' => $target),
|
||||||
|
array('return_rows' => Database::RETURN_ONE_ROW)
|
||||||
|
);
|
||||||
|
|
||||||
|
// There is no update with such target in database
|
||||||
|
if (!$info) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create and populate update object
|
||||||
|
$update = new self();
|
||||||
|
$update->populateFromDbFields($info);
|
||||||
|
|
||||||
|
return $update;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads available updates.
|
||||||
|
*
|
||||||
|
* @return array List of AvailableUpdate instances.
|
||||||
|
*
|
||||||
|
* @throws \RuntimeException If something went wrong and the list could not
|
||||||
|
* be loaded.
|
||||||
|
*/
|
||||||
|
public static function all()
|
||||||
|
{
|
||||||
|
$rows = Database::getInstance()->query(
|
||||||
|
"SELECT * FROM {availableupdate}",
|
||||||
|
null,
|
||||||
|
array('return_rows' => Database::RETURN_ALL_ROWS)
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($rows === false) {
|
||||||
|
throw new \RuntimeException('List of available updates cannot be retrieved.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$updates = array();
|
||||||
|
foreach ($rows as $item) {
|
||||||
|
$update = new self();
|
||||||
|
$update->populateFromDbFields($item);
|
||||||
|
$updates[] = $update;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $updates;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class constructor.
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
// Set default values
|
||||||
|
$this->id = false;
|
||||||
|
$this->target = null;
|
||||||
|
$this->version = null;
|
||||||
|
$this->url = '';
|
||||||
|
$this->description = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove record about available update from the database.
|
||||||
|
*/
|
||||||
|
public function delete()
|
||||||
|
{
|
||||||
|
if (!$this->id) {
|
||||||
|
throw new \RuntimeException('You cannot delete an update without id');
|
||||||
|
}
|
||||||
|
|
||||||
|
Database::getInstance()->query(
|
||||||
|
"DELETE FROM {availableupdate} WHERE id = :id LIMIT 1",
|
||||||
|
array(':id' => $this->id)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save the update to the database.
|
||||||
|
*/
|
||||||
|
public function save()
|
||||||
|
{
|
||||||
|
$db = Database::getInstance();
|
||||||
|
|
||||||
|
if (!$this->target) {
|
||||||
|
throw new \RuntimeException('Update\'s target was not set');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->url) {
|
||||||
|
throw new \RuntimeException('Update\'s URL was not set');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->version) {
|
||||||
|
throw new \RuntimeException('Update\'s version was not set');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->id) {
|
||||||
|
// This update is new.
|
||||||
|
$db->query(
|
||||||
|
("INSERT INTO {availableupdate} (target, version, url, description) "
|
||||||
|
. "VALUES (:target, :version, :url, :description)"),
|
||||||
|
array(
|
||||||
|
':target' => $this->target,
|
||||||
|
':version' => $this->version,
|
||||||
|
':url' => $this->url,
|
||||||
|
':description' => $this->description,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$this->id = $db->insertedId();
|
||||||
|
} else {
|
||||||
|
// Update existing update
|
||||||
|
$db->query(
|
||||||
|
("UPDATE {availableupdate} SET target = :target, url = :url, "
|
||||||
|
. "version = :version, description = :description "
|
||||||
|
. "WHERE id = :id"),
|
||||||
|
array(
|
||||||
|
':id' => $this->id,
|
||||||
|
':target' => $this->target,
|
||||||
|
':version' => $this->version,
|
||||||
|
':url' => $this->url,
|
||||||
|
':description' => $this->description,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets update's fields according to the fields from Database.
|
||||||
|
*
|
||||||
|
* @param array $db_fields Associative array of database fields which keys
|
||||||
|
* are fields names and the values are fields values.
|
||||||
|
*/
|
||||||
|
protected function populateFromDbFields($db_fields)
|
||||||
|
{
|
||||||
|
$this->id = $db_fields['id'];
|
||||||
|
$this->target = $db_fields['target'];
|
||||||
|
$this->version = $db_fields['version'];
|
||||||
|
$this->url = $db_fields['url'];
|
||||||
|
$this->description = $db_fields['description'];
|
||||||
|
}
|
||||||
|
}
|
@ -36,6 +36,13 @@ class CronWorker
|
|||||||
*/
|
*/
|
||||||
protected $cache = null;
|
protected $cache = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An instance of update checker.
|
||||||
|
*
|
||||||
|
* @var UpdateChecker|null
|
||||||
|
*/
|
||||||
|
protected $updateChecker = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List of errors.
|
* List of errors.
|
||||||
*
|
*
|
||||||
@ -54,10 +61,15 @@ class CronWorker
|
|||||||
* Class constructor.
|
* Class constructor.
|
||||||
*
|
*
|
||||||
* @param PoolInterface $cache An instance of cache pool.
|
* @param PoolInterface $cache An instance of cache pool.
|
||||||
|
* @param UpdateChecker $update_checker An instance of update checker.
|
||||||
*/
|
*/
|
||||||
public function __construct(PoolInterface $cache)
|
public function __construct(PoolInterface $cache, UpdateChecker $update_checker = null)
|
||||||
{
|
{
|
||||||
$this->cache = $cache;
|
$this->cache = $cache;
|
||||||
|
|
||||||
|
if (!is_null($update_checker)) {
|
||||||
|
$this->updateChecker = $update_checker;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -71,6 +83,9 @@ class CronWorker
|
|||||||
try {
|
try {
|
||||||
set_time_limit(0);
|
set_time_limit(0);
|
||||||
|
|
||||||
|
// Update time of last cron run
|
||||||
|
Settings::set('_last_cron_run', time());
|
||||||
|
|
||||||
// Remove stale cached items
|
// Remove stale cached items
|
||||||
$this->cache->purge();
|
$this->cache->purge();
|
||||||
|
|
||||||
@ -83,8 +98,18 @@ class CronWorker
|
|||||||
$dispatcher = EventDispatcher::getInstance();
|
$dispatcher = EventDispatcher::getInstance();
|
||||||
$dispatcher->triggerEvent(Events::CRON_RUN);
|
$dispatcher->triggerEvent(Events::CRON_RUN);
|
||||||
|
|
||||||
// Update time of last cron run
|
if (Settings::get('autocheckupdates') == '1') {
|
||||||
Settings::set('_last_cron_run', time());
|
// Run the update checker
|
||||||
|
$update_checker = $this->getUpdateChecker();
|
||||||
|
if (!$update_checker->run()) {
|
||||||
|
$this->errors = array_merge(
|
||||||
|
$this->errors,
|
||||||
|
$update_checker->getErrors()
|
||||||
|
);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
$this->log[] = $e->getMessage();
|
$this->log[] = $e->getMessage();
|
||||||
|
|
||||||
@ -114,4 +139,24 @@ class CronWorker
|
|||||||
{
|
{
|
||||||
return $this->log;
|
return $this->log;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrives an instance of Update Checker attached to the worker.
|
||||||
|
*
|
||||||
|
* If there was no attached checker it creates a new one.
|
||||||
|
*
|
||||||
|
* @return UpdateChecker
|
||||||
|
*/
|
||||||
|
protected function getUpdateChecker()
|
||||||
|
{
|
||||||
|
if (is_null($this->updateChecker)) {
|
||||||
|
$this->updateChecker = new UpdateChecker();
|
||||||
|
$id = Settings::get('_instance_id');
|
||||||
|
if ($id) {
|
||||||
|
$this->updateChecker->setInstanceId($id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->updateChecker;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -440,6 +440,46 @@ class Installer
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Generate Unique ID for Mibew Instance
|
||||||
|
try {
|
||||||
|
list($count) = $db->query(
|
||||||
|
'SELECT COUNT(*) FROM {config} WHERE vckey = :key',
|
||||||
|
array(':key' => '_instance_id'),
|
||||||
|
array(
|
||||||
|
'return_rows' => Database::RETURN_ONE_ROW,
|
||||||
|
'fetch_type' => Database::FETCH_NUM,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($count == 0) {
|
||||||
|
$db->query(
|
||||||
|
'INSERT INTO {config} (vckey, vcvalue) VALUES (:key, :value)',
|
||||||
|
array(
|
||||||
|
':key' => '_instance_id',
|
||||||
|
':value' => Utils::generateInstanceId(),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// The option is already in the database. It seems that
|
||||||
|
// something went wrong with the previous installation attempt.
|
||||||
|
// Just update the instance ID.
|
||||||
|
$db->query(
|
||||||
|
'UPDATE {config} SET vcvalue = :value WHERE vckey = :key',
|
||||||
|
array(
|
||||||
|
':key' => '_instance_id',
|
||||||
|
':value' => Utils::generateInstanceId(),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$this->errors[] = getlocal(
|
||||||
|
'Cannot store instance ID. Error {0}',
|
||||||
|
array($e->getMessage())
|
||||||
|
);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -489,7 +529,7 @@ class Installer
|
|||||||
*/
|
*/
|
||||||
protected function checkPhpExtensions()
|
protected function checkPhpExtensions()
|
||||||
{
|
{
|
||||||
$extensions = array('PDO', 'pdo_mysql', 'gd');
|
$extensions = array('PDO', 'pdo_mysql', 'gd', 'curl');
|
||||||
|
|
||||||
foreach ($extensions as $ext) {
|
foreach ($extensions as $ext) {
|
||||||
if (!extension_loaded($ext)) {
|
if (!extension_loaded($ext)) {
|
||||||
|
371
src/mibew/libs/classes/Mibew/Maintenance/UpdateChecker.php
Normal file
371
src/mibew/libs/classes/Mibew/Maintenance/UpdateChecker.php
Normal file
@ -0,0 +1,371 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is a part of Mibew Messenger.
|
||||||
|
*
|
||||||
|
* Copyright 2005-2015 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Mibew\Maintenance;
|
||||||
|
|
||||||
|
use Mibew\Plugin\Utils as PluginUtils;
|
||||||
|
use Mibew\Plugin\PluginInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encapsulates available updates checking process.
|
||||||
|
*/
|
||||||
|
class UpdateChecker
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* URL of the updates server.
|
||||||
|
*
|
||||||
|
* @var string|null
|
||||||
|
*/
|
||||||
|
private $url = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unique 64 character length ID of the Mibew instance.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $instanceId = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A cache for plugins info array.
|
||||||
|
*
|
||||||
|
* @var array|null
|
||||||
|
*/
|
||||||
|
private $pluginsInfo = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of errors that took place during updates checking.
|
||||||
|
*
|
||||||
|
* Each item of the list is a error string.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
private $errors = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets URL of updates server.
|
||||||
|
*
|
||||||
|
* @param string $url New updates server's URL
|
||||||
|
*/
|
||||||
|
public function setUrl($url)
|
||||||
|
{
|
||||||
|
$this->url = $url;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves URL of updates server.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getUrl()
|
||||||
|
{
|
||||||
|
return is_null($this->url)
|
||||||
|
? 'https://mibew.org/api2/updates.json'
|
||||||
|
: $this->url;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets Unique ID of the Mibew instance.
|
||||||
|
*
|
||||||
|
* @param string $id Unique ID that is 64 characters length at most.
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
*/
|
||||||
|
public function setInstanceId($id)
|
||||||
|
{
|
||||||
|
if (strlen($id) > 64) {
|
||||||
|
throw new \InvalidArgumentException(
|
||||||
|
'The ID is too long. It can be 64 characters length at most.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure the ID is always a string.
|
||||||
|
$this->instanceId = $id ?: '';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve Unique ID of the Mibew instance.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getInstanceId()
|
||||||
|
{
|
||||||
|
return $this->instanceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves list of errors that took place during update checking process.
|
||||||
|
*
|
||||||
|
* @return array List of errors. Each item in the list is a error string.
|
||||||
|
*/
|
||||||
|
public function getErrors()
|
||||||
|
{
|
||||||
|
return $this->errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs update checking process.
|
||||||
|
*
|
||||||
|
* @return boolean False on error and true otherwise. To get more info about
|
||||||
|
* error call {@link UpdateChecker::getErrors()} method.
|
||||||
|
*/
|
||||||
|
public function run()
|
||||||
|
{
|
||||||
|
$ch = curl_init($this->getUrl());
|
||||||
|
|
||||||
|
// TODO: set timeouts
|
||||||
|
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
|
||||||
|
curl_setopt($ch, CURLOPT_POST, true);
|
||||||
|
curl_setopt($ch, CURLOPT_MAXREDIRS, 5);
|
||||||
|
|
||||||
|
$json = json_encode($this->getSystemInfo());
|
||||||
|
curl_setopt($ch, CURLOPT_POSTFIELDS, $json);
|
||||||
|
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
|
||||||
|
'Accept: application/json',
|
||||||
|
'Content-Type: application/json',
|
||||||
|
'Content-Length: ' . strlen($json)
|
||||||
|
));
|
||||||
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||||
|
|
||||||
|
$body = curl_exec($ch);
|
||||||
|
$response_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||||
|
$curl_errno = curl_errno($ch);
|
||||||
|
$curl_error = curl_error($ch);
|
||||||
|
curl_close($ch);
|
||||||
|
|
||||||
|
if ($curl_errno !== 0) {
|
||||||
|
// cURL request failed.
|
||||||
|
$this->errors[] = sprintf(
|
||||||
|
'cURL error (#%u): %s',
|
||||||
|
$curl_errno,
|
||||||
|
$curl_error
|
||||||
|
);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($response_code != 200) {
|
||||||
|
// Unexpected HTTP recieved.
|
||||||
|
$this->errors[] = sprintf(
|
||||||
|
'Update server returns %u HTTP code instead of 200',
|
||||||
|
$response_code
|
||||||
|
);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$updates = json_decode($body, true);
|
||||||
|
$json_error = json_last_error();
|
||||||
|
if ($json_error !== JSON_ERROR_NONE) {
|
||||||
|
// Cannot parse JSON result.
|
||||||
|
$this->errors[] = $this->formatJsonError($json_error);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$updates) {
|
||||||
|
// There are no available updates.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->processUpdates($updates);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves set of system info that will be sent to updates server.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
protected function getSystemInfo()
|
||||||
|
{
|
||||||
|
$info = array(
|
||||||
|
'core' => MIBEW_VERSION,
|
||||||
|
'plugins' => $this->getPluginsInfo(),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Attach Instance ID to the info but only if it's not empty.
|
||||||
|
$id = $this->getInstanceId();
|
||||||
|
if ($id) {
|
||||||
|
$info['uid'] = $id;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $info;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves info about plugins available in the system.
|
||||||
|
*
|
||||||
|
* @return array Associative array of plugins info. Each key of the array is
|
||||||
|
* fully qualified plugin's name and each value is an array with the
|
||||||
|
* fillowing keys:
|
||||||
|
* - "version": string, version of the plugin which presents in the system.
|
||||||
|
* - "installed": boolean, indicates if the plugin is installed.
|
||||||
|
* - "enabled": boolean, indicates if the plugin is enabled.
|
||||||
|
*/
|
||||||
|
protected function getPluginsInfo()
|
||||||
|
{
|
||||||
|
if (is_null($this->pluginsInfo)) {
|
||||||
|
$this->pluginsInfo = [];
|
||||||
|
$names = PluginUtils::discoverPlugins();
|
||||||
|
foreach ($names as $plugin_name) {
|
||||||
|
$info = new PluginInfo($plugin_name);
|
||||||
|
$this->pluginsInfo[$plugin_name] = array(
|
||||||
|
'version' => $info->getVersion(),
|
||||||
|
'installed' => $info->getState()->installed,
|
||||||
|
'enabled' => $info->getState()->enabled,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->pluginsInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs all actions that are needed to prepare store available updates.
|
||||||
|
*
|
||||||
|
* @param array $updates Asscociative array of available updates that is
|
||||||
|
* retrieved from the updates server.
|
||||||
|
* @return boolean False on error and true otherwise. To get more info about
|
||||||
|
* error call {@link UpdateChecker::getErrors()} method.
|
||||||
|
*/
|
||||||
|
protected function processUpdates($updates)
|
||||||
|
{
|
||||||
|
// Process updates of the core.
|
||||||
|
if (version_compare($updates['core']['version'], MIBEW_VERSION) > 0) {
|
||||||
|
$update = $updates['core'];
|
||||||
|
// Save info about update for the core only if its version changed
|
||||||
|
$success = $this->saveUpdate(
|
||||||
|
'core',
|
||||||
|
$update['version'],
|
||||||
|
$update['download'],
|
||||||
|
empty($update['description']) ? '' : $update['description']
|
||||||
|
);
|
||||||
|
if (!$success) {
|
||||||
|
// Something went wrong. The error is already logged so just
|
||||||
|
// notify the outer code.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process plugins updates.
|
||||||
|
$plugins_info = $this->getPluginsInfo();
|
||||||
|
foreach ($updates['plugins'] as $plugin_name => $update) {
|
||||||
|
if (!isset($plugins_info[$plugin_name])) {
|
||||||
|
// It's strange. We recieve update info for a plugin that does
|
||||||
|
// not exist in the system. Just do nothing.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$info = $plugins_info[$plugin_name];
|
||||||
|
|
||||||
|
if (version_compare($update['version'], $info['version']) <= 0) {
|
||||||
|
// Version of the plugin is not updated. Just do nothing.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save the update
|
||||||
|
$success = $this->saveUpdate(
|
||||||
|
$plugin_name,
|
||||||
|
$update['version'],
|
||||||
|
$update['download'],
|
||||||
|
empty($update['description']) ? '' : $update['description']
|
||||||
|
);
|
||||||
|
if (!$success) {
|
||||||
|
// Something went wrong. The error is already logged so just
|
||||||
|
// notify the outer code.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves record about available update in the database.
|
||||||
|
*
|
||||||
|
* @param string $target Update's target. Can be either "core" or fully
|
||||||
|
* qualified plugin's name.
|
||||||
|
* @param string $version The latest version at the updates server.
|
||||||
|
* @param string $url URL of the page where the update can be downloaded.
|
||||||
|
* @param string $description Arbitrary update's description.
|
||||||
|
* @return boolean False on failure and true otherwise. To get more info
|
||||||
|
* about the error call {@link UpdateChecker::getErrors()} method.
|
||||||
|
*/
|
||||||
|
protected function saveUpdate($target, $version, $url, $description = '')
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$update = AvailableUpdate::loadByTarget($target);
|
||||||
|
if (!$update) {
|
||||||
|
// There is no such update in the database. Create a new one.
|
||||||
|
$update = new AvailableUpdate();
|
||||||
|
$update->target = $target;
|
||||||
|
}
|
||||||
|
|
||||||
|
$update->version = $version;
|
||||||
|
$update->url = $url;
|
||||||
|
$update->description = $description;
|
||||||
|
|
||||||
|
$update->save();
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$this->errors[] = 'Cannot save available update: ' + $e->getMessage();
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds human-readable message about error in json_* PHP's function.
|
||||||
|
*
|
||||||
|
* @param int $error_code Error code returned by json_last_error
|
||||||
|
* @return string Human-readable error message.
|
||||||
|
*/
|
||||||
|
protected function formatJsonError($error_code)
|
||||||
|
{
|
||||||
|
$errors = array(
|
||||||
|
JSON_ERROR_DEPTH => 'JSON_ERROR_DEPTH',
|
||||||
|
JSON_ERROR_STATE_MISMATCH => 'JSON_ERROR_STATE_MISMATCH',
|
||||||
|
JSON_ERROR_CTRL_CHAR => 'JSON_ERROR_CTRL_CHAR',
|
||||||
|
JSON_ERROR_SYNTAX => 'JSON_ERROR_SYNTAX',
|
||||||
|
);
|
||||||
|
|
||||||
|
// Following constants may be unavailable for the current PHP version.
|
||||||
|
if (defined('JSON_ERROR_UTF8')) {
|
||||||
|
$errors[JSON_ERROR_UTF8] = 'JSON_ERROR_UTF8';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (defined('JSON_ERROR_RECURSION')) {
|
||||||
|
$errors[JSON_ERROR_RECURSION] = 'JSON_ERROR_RECURSION';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (defined('JSON_ERROR_INF_OR_NAN')) {
|
||||||
|
$errors[JSON_ERROR_INF_OR_NAN] = 'JSON_ERROR_INF_OR_NAN';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (defined('JSON_ERROR_UNSUPPORTED_TYPE')) {
|
||||||
|
$errors[JSON_ERROR_UNSUPPORTED_TYPE] = 'JSON_ERROR_UNSUPPORTED_TYPE';
|
||||||
|
}
|
||||||
|
|
||||||
|
$msg = isset($errors[$error_code]) ? $errors[$error_code] : 'UNKNOWN';
|
||||||
|
|
||||||
|
return sprintf(
|
||||||
|
'Could not parse response from update server. The error is: "%s"',
|
||||||
|
$msg
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -332,14 +332,33 @@ class Updater
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Alter locale table.
|
|
||||||
try {
|
try {
|
||||||
|
// Alter locale table.
|
||||||
$db->query('ALTER TABLE {locale} ADD COLUMN name varchar(128) NOT NULL DEFAULT "" AFTER code');
|
$db->query('ALTER TABLE {locale} ADD COLUMN name varchar(128) NOT NULL DEFAULT "" AFTER code');
|
||||||
$db->query('ALTER TABLE {locale} ADD COLUMN rtl tinyint NOT NULL DEFAULT 0');
|
$db->query('ALTER TABLE {locale} ADD COLUMN rtl tinyint NOT NULL DEFAULT 0');
|
||||||
$db->query('ALTER TABLE {locale} ADD COLUMN time_locale varchar(128) NOT NULL DEFAULT "en_US"');
|
$db->query('ALTER TABLE {locale} ADD COLUMN time_locale varchar(128) NOT NULL DEFAULT "en_US"');
|
||||||
$db->query('ALTER TABLE {locale} ADD COLUMN date_format text');
|
$db->query('ALTER TABLE {locale} ADD COLUMN date_format text');
|
||||||
|
|
||||||
$db->query('ALTER TABLE {locale} ADD UNIQUE KEY code (code)');
|
$db->query('ALTER TABLE {locale} ADD UNIQUE KEY code (code)');
|
||||||
|
|
||||||
|
// Create a table for available updates.
|
||||||
|
$db->query('CREATE TABLE {availableupdate} ( '
|
||||||
|
. 'id INT NOT NULL auto_increment PRIMARY KEY, '
|
||||||
|
. 'target varchar(255) NOT NULL, '
|
||||||
|
. 'version varchar(255) NOT NULL, '
|
||||||
|
. 'url text, '
|
||||||
|
. 'description text, '
|
||||||
|
. 'UNIQUE KEY target (target) '
|
||||||
|
. ') charset utf8 ENGINE=InnoDb');
|
||||||
|
|
||||||
|
// Generate Unique ID of Mibew instance.
|
||||||
|
$db->query(
|
||||||
|
'INSERT INTO {config} (vckey, vcvalue) VALUES (:key, :value)',
|
||||||
|
array(
|
||||||
|
':key' => '_instance_id',
|
||||||
|
':value' => Utils::generateInstanceId(),
|
||||||
|
)
|
||||||
|
);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
$this->errors[] = getlocal('Cannot update tables: {0}', $e->getMessage());
|
$this->errors[] = getlocal('Cannot update tables: {0}', $e->getMessage());
|
||||||
|
|
||||||
|
@ -101,6 +101,40 @@ class Utils
|
|||||||
return $updates;
|
return $updates;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates random unique 64 characters length ID for Mibew instance.
|
||||||
|
*
|
||||||
|
* WARNING: This ID should not be used for any security/cryptographic. If
|
||||||
|
* you need an ID for such purpose you have to use PHP's
|
||||||
|
* {@link openssl_random_pseudo_bytes()} function instead.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function generateInstanceId()
|
||||||
|
{
|
||||||
|
$chars = '0123456789abcdefghijklmnopqrstuvwxyz';
|
||||||
|
$rnd = (string)microtime(true);
|
||||||
|
|
||||||
|
// Add ten random characters before and after the timestamp
|
||||||
|
$max_char = strlen($chars) - 1;
|
||||||
|
for ($i = 0; $i < 10; $i++) {
|
||||||
|
$rnd = $chars[rand(0, $max_char)] . $rnd . $chars[rand(0, $max_char)];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (function_exists('hash')) {
|
||||||
|
// There is hash function that can give us 64-length hash.
|
||||||
|
return hash('sha256', $rnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
// We should build random 64 character length hash using old'n'good md5
|
||||||
|
// function.
|
||||||
|
$middle = (int)floor(strlen($rnd) / 2);
|
||||||
|
$rnd_left = substr($rnd, 0, $middle);
|
||||||
|
$rnd_right = substr($rnd, $middle);
|
||||||
|
|
||||||
|
return md5($rnd_left) . md5($rnd_right);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class should not be instantiated
|
* This class should not be instantiated
|
||||||
*/
|
*/
|
||||||
|
@ -97,6 +97,7 @@ class Settings
|
|||||||
'surveyaskgroup' => '1',
|
'surveyaskgroup' => '1',
|
||||||
'surveyaskmessage' => '0',
|
'surveyaskmessage' => '0',
|
||||||
'enablepopupnotification' => '0',
|
'enablepopupnotification' => '0',
|
||||||
|
'autocheckupdates' => '1', /* Check updates automatically */
|
||||||
'showonlineoperators' => '0',
|
'showonlineoperators' => '0',
|
||||||
'enablecaptcha' => '0',
|
'enablecaptcha' => '0',
|
||||||
'online_timeout' => 30, /* Timeout (in seconds) when online operator becomes offline */
|
'online_timeout' => 30, /* Timeout (in seconds) when online operator becomes offline */
|
||||||
@ -114,6 +115,10 @@ class Settings
|
|||||||
// underscore sign(_).
|
// underscore sign(_).
|
||||||
// Unix timestamp when cron job ran last time.
|
// Unix timestamp when cron job ran last time.
|
||||||
'_last_cron_run' => 0,
|
'_last_cron_run' => 0,
|
||||||
|
// Random unique ID which is used for getting info about new
|
||||||
|
// updates. This value is initialized during Installation or Update
|
||||||
|
// process.
|
||||||
|
'_instance_id' => '',
|
||||||
);
|
);
|
||||||
|
|
||||||
// Load values from database
|
// Load values from database
|
||||||
|
@ -22,11 +22,6 @@
|
|||||||
|
|
||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
<h3>{{l10n "Latest version:"}}</h3>
|
|
||||||
<div id="latest-version"></div>
|
|
||||||
|
|
||||||
<br/>
|
|
||||||
|
|
||||||
<h3>{{l10n "Installed localizations:"}}</h3>
|
<h3>{{l10n "Installed localizations:"}}</h3>
|
||||||
{{#each localizations}}
|
{{#each localizations}}
|
||||||
{{this}}
|
{{this}}
|
||||||
@ -36,6 +31,26 @@
|
|||||||
|
|
||||||
<h3>{{l10n "Environment:"}}</h3>
|
<h3>{{l10n "Environment:"}}</h3>
|
||||||
PHP {{phpVersion}} {{#each extensions}}{{@key}}{{#if loaded}}{{#if version}}/{{version}}{{/if}}{{else}}/absent{{/if}} {{/each}}
|
PHP {{phpVersion}} {{#each extensions}}{{@key}}{{#if loaded}}{{#if version}}/{{version}}{{/if}}{{else}}/absent{{/if}} {{/each}}
|
||||||
|
|
||||||
|
<br/><br/>
|
||||||
|
|
||||||
|
<h2>{{l10n "Available updates"}}</h2>
|
||||||
|
{{#if availableUpdates}}
|
||||||
|
{{#each availableUpdates}}
|
||||||
|
<h3>{{title}} ({{version}})</h3>
|
||||||
|
{{#if description}}
|
||||||
|
<div>{{description}}</div>
|
||||||
|
{{/if}}
|
||||||
|
<div>
|
||||||
|
<a href="{{url}}">Download</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
{{/each}}
|
||||||
|
{{else}}
|
||||||
|
There is no available updates.<br/><br/>
|
||||||
|
{{/if}}
|
||||||
|
<a href="{{route "update_check"}}">{{l10n "Check for available updates"}}</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-footer">
|
<div class="form-footer">
|
||||||
|
@ -172,6 +172,15 @@
|
|||||||
<br clear="all"/>
|
<br clear="all"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="field">
|
||||||
|
<label for="autocheck-updates" class="field-label">{{l10n "Check updates automatically"}}</label>
|
||||||
|
<div class="field-value">
|
||||||
|
<input id="autocheck-updates" type="checkbox" name="autocheckupdates" value="on"{{#if formautocheckupdates}} checked="checked"{{/if}}{{#unless canmodify}} disabled="disabled"{{/unless}}/>
|
||||||
|
</div>
|
||||||
|
<label for="autocheck-updates" class="field-description"> — {{l10n "System will check updates for the core and plugins automatically using cron"}}</label>
|
||||||
|
<br clear="all"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
{{#if canmodify}}
|
{{#if canmodify}}
|
||||||
<div class="form-button">
|
<div class="form-button">
|
||||||
<input type="submit" name="save" class="submit-button-background save-button" value="{{l10n "Save"}}"/>
|
<input type="submit" name="save" class="submit-button-background save-button" value="{{l10n "Save"}}"/>
|
||||||
|
Loading…
Reference in New Issue
Block a user