1.x - Rrajigar Mine
* Fixed install sql file.
* New field: artists - lookupmultiple field
- * Added setup file. See setup/install.txt for more details
+ * Added setup process. See setup/install.txt for more details
+ * Stats info page
1.2 - NyLeve's Falls 20210717
* Updated requirements information
* Automatic upgrades of DB
-* stats overview page. amount of entries. file / cache and db storage. Version info and where to find it.
* Definition of fields in "card view"
* User and groupmanagement: Check where a user or group is used!
* Better error handling and display while adding / update and delete
* A Webserver (tested on Apache 2.4)
* PHP 7+ with mysqli, mbstring, curl
* MySQL 8+; MariaDB 10.2/MySQL 8
+-- User with full rights on the Database. Including lock tables
* At least 20MB webserver storage WITHOUT images
-* At least 100MB DB storage.
+* At least 20MB DB storage.
`position` int NOT NULL DEFAULT '0',
`category` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
PRIMARY KEY (`id`)
-) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
+) ENGINE=InnoDB AUTO_INCREMENT=20 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
LOCK TABLES `#REPLACEME#_menu` WRITE;
/*!40000 ALTER TABLE `#REPLACEME#_menu` DISABLE KEYS */;
-INSERT INTO `#REPLACEME#_menu` VALUES (1,'Dashboard','','home',1,1,'rw-r--r--',0,'show'),(2,'Collections','collections','database',1,1,'rw-r--r--',1,'show'),(3,'Tags','tags','tag',1,1,'rw-r--r--',2,'show'),(4,'Add','manageentry','plus-circle',1,2,'rw-rw----',0,'manage'),(6,'Tags','managetags','tag',1,2,'rw-rw----',2,'manage'),(7,'Collections','managecolletions','database',1,2,'rw-rw----',3,'manage'),(8,'Users','manageusers','users',1,1,'rw-------',4,'manage'),(9,'Login','auth','',1,1,'rw-r--r--',0,''),(10,'Collection fields','managecollectionfields','',1,2,'rw-rw----',0,''),(11,'Entry','entry','',1,1,'rw-r--r--',0,''),(12,'Search','search','',1,1,'rw-r--r--',0,''),(14,'Tool','tool','',1,2,'rw-rw----',0,''),(15,'Advanced search','advancedsearch','',1,1,'rw-r--r--',0,''),(16,'Profile','profile','user',1,2,'rw-rw----',6,'manage'),(17,'Groups','managegroups','users',1,1,'rw-------',5,'manage'),(18,'Bulkedit','bulkedit','',1,2,'rw-rw----',0,'');
+INSERT INTO `#REPLACEME#_menu` VALUES (1,'Dashboard','','home',1,1,'rw-r--r--',0,'show'),(2,'Collections','collections','database',1,1,'rw-r--r--',1,'show'),(3,'Tags','tags','tag',1,1,'rw-r--r--',2,'show'),(4,'Add','manageentry','plus-circle',1,2,'rw-rw----',0,'manage'),(6,'Tags','managetags','tag',1,2,'rw-rw----',2,'manage'),(7,'Collections','managecolletions','database',1,2,'rw-rw----',3,'manage'),(8,'Users','manageusers','users',1,1,'rw-------',4,'manage'),(9,'Login','auth','',1,1,'rw-r--r--',0,''),(10,'Collection fields','managecollectionfields','',1,2,'rw-rw----',0,''),(11,'Entry','entry','',1,1,'rw-r--r--',0,''),(12,'Search','search','',1,1,'rw-r--r--',0,''),(14,'Tool','tool','',1,2,'rw-rw----',0,''),(15,'Advanced search','advancedsearch','',1,1,'rw-r--r--',0,''),(16,'Profile','profile','user',1,2,'rw-rw----',6,'manage'),(17,'Groups','managegroups','users',1,1,'rw-------',5,'manage'),(18,'Bulkedit','bulkedit','',1,2,'rw-rw----',0,''),(19,'System Information','sysinfo','info',1,1,'rw-------',3,'show');
/*!40000 ALTER TABLE `#REPLACEME#_menu` ENABLE KEYS */;
UNLOCK TABLES;
Login with default admin account and change the password!
Create your own user.
Create your first collection.
+
+To re run the setup:
+Upload the setup folder again. It deletes itself after a successfull setup
- sql file mit mysqldump
- config files in setup.php
- options in setup.php
+- sql file in setup
documentation
version, readme and changelog
-upgrade file
+upgrade file with correct placeholders
-correct placeholders
+correct placeholders in sql file for manual setup
+
+correct version info in VERSION and index.php
# DB changes. Run each line against your bibliotheca DB.
# Replace #REPLACEME# with your table prefix. Default is bib
INSERT INTO `#REPLACEME#_sys_fields` (`id`, `identifier`, `displayname`, `type`, `searchtype`, `createstring`, `inputValidation`, `value`, `apiinfo`, `created`, `modified`, `modificationuser`, `owner`, `group`, `rights`) VALUES (NULL, 'artists', 'Artists', 'lookupmultiple', 'tag', NULL, 'allowSpace', NULL, 'string 64', NOW(), NOW(), NULL, '1', '1', 'rw-r--r--');
+INSERT INTO `#REPLACEME#_menu` (`id`, `text`, `action`, `icon`, `owner`, `group`, `rights`, `position`, `category`) VALUES (NULL, 'System Information', 'sysinfo', 'info', '1', '1', 'rw-------', '3', 'show');
require_once './config/config.php';
+define('BIB_VERSION','1.x - Rrajigar Mine ()');
+
mb_http_output('UTF-8');
mb_internal_encoding('UTF-8');
ini_set('error_reporting',-1); // E_ALL & E_STRICT
* @param bool $tableName
* @return string
*/
- public function getSQLRightsString($mode = "read", $tableName=false) {
+ public function getSQLRightsString($mode = "read", $tableName=false): string {
$str = '';
$prefix = '';
* @param mysqli $databaseConnectionObject
* @param Doomguy $userObj
*/
- public function __construct($databaseConnectionObject, $userObj) {
+ public function __construct(mysqli $databaseConnectionObject, Doomguy $userObj) {
$this->_DB = $databaseConnectionObject;
$this->_User = $userObj;
}
- /**
- * Load collection info from table. Checks user rights
- *
- * @param string $id
- * @param string $rightsMode
- * @return array
- */
- public function getCollection($id,$rightsMode="read") {
- $ret = array();
-
- if (Summoner::validate($id, 'digit')) {
- $queryStr = "SELECT `c`.`id`, `c`.`name`, `c`.`description`, `c`.`created`
- FROM `".DB_PREFIX."_collection` AS c
- WHERE ".$this->_User->getSQLRightsString($rightsMode, "c")."
- AND `c`.`id` = '".$this->_DB->real_escape_string($id)."'";
- if(QUERY_DEBUG) error_log("[QUERY] ".__METHOD__." query: ".var_export($queryStr,true));
- try {
- $query = $this->_DB->query($queryStr);
- if ($query !== false && $query->num_rows > 0) {
- $ret = $query->fetch_assoc();
- }
- }
- catch (Exception $e) {
- error_log("[ERROR] ".__METHOD__." mysql catch: ".$e->getMessage());
- }
- }
-
- return $ret;
- }
-
/**
* Get all available collections for display based on current user
*
* @return array
*/
- public function getCollections() {
+ public function getCollections(): array{
$ret = array();
$queryStr = "SELECT `c`.`id`, `c`.`name`, `c`.`description`, `c`.`created`,
if(QUERY_DEBUG) error_log("[QUERY] ".__METHOD__." query: ".var_export($queryStr,true));
try {
$query = $this->_DB->query($queryStr);
-
if ($query !== false && $query->num_rows > 0) {
while (($result = $query->fetch_assoc()) != false) {
$ret[$result['id']] = $result;
return $ret;
}
+
+ /**
+ * Size of the folder and the data within in bytes
+ *
+ * @param string $dir
+ * @return int
+ */
+ static function folderSize(string $dir): int {
+ $size = 0;
+
+ foreach (glob(rtrim($dir, '/').'/*', GLOB_NOSORT) as $each) {
+ $size += is_file($each) ? filesize($each) : self::folderSize($each);
+ }
+
+ return $size;
+ }
+
+ /**
+ * Given bytes to human format with unit
+ *
+ * @param int $bytes
+ * @return string
+ */
+ static function bytesToHuman(int $bytes): string {
+ $units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'];
+ for ($i = 0; $bytes > 1024; $i++) {
+ $bytes /= 1024;
+ }
+ return round($bytes, 2) . ' ' . $units[$i];
+ }
}
}
/**
- * Get information to display for current collection
+ * Get information to display for given collection
* based on current user and given rights
*
* @param string $id The collection ID to load
* get the value of the specified param from the collection data array
*
* @param string $param
- * @return bool|mixed
+ * @return string
*/
- public function param($param) {
- $ret = false;
+ public function param(string $param): string {
+ $ret = '';
$param = trim($param);
* Get all available collections for display based on current user
* and read mode
*
+ * @param string $rightsMode
* @return array
*/
- public function getCollections($rightsMode="read") {
+ public function getCollections($rightsMode="read"): array {
$ret = array();
$queryStr = "SELECT `c`.`id`, `c`.`name`, `c`.`description`
* @param string $search String value to search value against
* @return array
*/
- public function getTags($search='') {
+ public function getTags($search=''): array {
$ret = array();
$queryStr = "SELECT `cf`.`fk_field_id` AS id,
*
* @return array
*/
- public function getAvailableTools() {
+ public function getAvailableTools(): array {
$ret = array();
$queryStr = "SELECT `t`.`id`, `t`.`name`, `t`.`description`, `t`.`action`, `t`.`target`
return $ret;
}
+ /**
+ * Some statistics about the current collection.
+ * Entries, tags, storage
+ * Adds a stats array to _collectionData
+ *
+ * @return array
+ */
+ public function getStats(): array {
+ if(empty($this->_id)) return array();
+
+ $this->_collectionData['stats'] = array();
+
+ $queryStr = "SELECT COUNT(*) AS entries FROM `".DB_PREFIX."_collection_entry_".$this->_id."`";
+ if(QUERY_DEBUG) error_log("[QUERY] ".__METHOD__." query: ".var_export($queryStr,true));
+ try {
+ $query = $this->_DB->query($queryStr);
+ if($query !== false && $query->num_rows > 0) {
+ $result = $query->fetch_assoc();
+ $this->_collectionData['stats']['entriesCount'] = $result['entries'];
+ }
+ }
+ catch (Exception $e) {
+ error_log("[ERROR] ".__METHOD__." mysql catch: ".$e->getMessage());
+ }
+
+ $tags = $this->getTags();
+ $tagsCount = 0;
+ foreach ($tags as $k=>$v) {
+ $tagsCount += count($v['entries']);
+ }
+ $this->_collectionData['stats']['tagsCount'] = $tagsCount;
+
+ $tableSize = 0; // in MB
+ $queryStr = "SELECT (DATA_LENGTH + INDEX_LENGTH) AS `size`
+ FROM information_schema.TABLES
+ WHERE TABLE_SCHEMA = 'bibliotheca'
+ AND TABLE_NAME LIKE 'bib_collection_%_".$this->_id."'
+ ORDER BY (DATA_LENGTH + INDEX_LENGTH) DESC";
+ if(QUERY_DEBUG) error_log("[QUERY] ".__METHOD__." query: ".var_export($queryStr,true));
+ try {
+ $query = $this->_DB->query($queryStr);
+ if($query !== false && $query->num_rows > 0) {
+ while(($result = $query->fetch_assoc()) != false) {
+ $tableSize += $result['size'];
+ }
+ }
+ }
+ catch (Exception $e) {
+ error_log("[ERROR] ".__METHOD__." mysql catch: ".$e->getMessage());
+ }
+ $this->_collectionData['stats']['tableSize'] = Summoner::bytesToHuman($tableSize);
+
+ $this->_collectionData['stats']['storageSize'] = Summoner::bytesToHuman(Summoner::folderSize(PATH_STORAGE.'/'.$this->_id));
+
+
+ return $this->_collectionData;
+ }
+
/**
* set some defaults by init of the class
*
/**
* Make a key=>value array of a comma seperated string and use the value as key
*
- * @param array $data
+ * @param string $data
* @return array
*/
- private function _loadAdvancedSearchTableFields($data) {
+ private function _loadAdvancedSearchTableFields(string $data): array {
$ret = array();
- $_t = explode(',',$data);
- foreach($_t as $e) {
- $ret[$e] = $e;
+ if(!strstr($data, ',')) {
+ $ret[$data] = $data;
+ }
+ else {
+ $_t = explode(',',$data);
+ foreach($_t as $e) {
+ $ret[$e] = $e;
+ }
}
return $ret;
`position` int NOT NULL DEFAULT '0',
`category` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
PRIMARY KEY (`id`)
-) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
+) ENGINE=InnoDB AUTO_INCREMENT=20 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
LOCK TABLES `#REPLACEME#_menu` WRITE;
/*!40000 ALTER TABLE `#REPLACEME#_menu` DISABLE KEYS */;
-INSERT INTO `#REPLACEME#_menu` VALUES (1,'Dashboard','','home',1,1,'rw-r--r--',0,'show'),(2,'Collections','collections','database',1,1,'rw-r--r--',1,'show'),(3,'Tags','tags','tag',1,1,'rw-r--r--',2,'show'),(4,'Add','manageentry','plus-circle',1,2,'rw-rw----',0,'manage'),(6,'Tags','managetags','tag',1,2,'rw-rw----',2,'manage'),(7,'Collections','managecolletions','database',1,2,'rw-rw----',3,'manage'),(8,'Users','manageusers','users',1,1,'rw-------',4,'manage'),(9,'Login','auth','',1,1,'rw-r--r--',0,''),(10,'Collection fields','managecollectionfields','',1,2,'rw-rw----',0,''),(11,'Entry','entry','',1,1,'rw-r--r--',0,''),(12,'Search','search','',1,1,'rw-r--r--',0,''),(14,'Tool','tool','',1,2,'rw-rw----',0,''),(15,'Advanced search','advancedsearch','',1,1,'rw-r--r--',0,''),(16,'Profile','profile','user',1,2,'rw-rw----',6,'manage'),(17,'Groups','managegroups','users',1,1,'rw-------',5,'manage'),(18,'Bulkedit','bulkedit','',1,2,'rw-rw----',0,'');
+INSERT INTO `#REPLACEME#_menu` VALUES (1,'Dashboard','','home',1,1,'rw-r--r--',0,'show'),(2,'Collections','collections','database',1,1,'rw-r--r--',1,'show'),(3,'Tags','tags','tag',1,1,'rw-r--r--',2,'show'),(4,'Add','manageentry','plus-circle',1,2,'rw-rw----',0,'manage'),(6,'Tags','managetags','tag',1,2,'rw-rw----',2,'manage'),(7,'Collections','managecolletions','database',1,2,'rw-rw----',3,'manage'),(8,'Users','manageusers','users',1,1,'rw-------',4,'manage'),(9,'Login','auth','',1,1,'rw-r--r--',0,''),(10,'Collection fields','managecollectionfields','',1,2,'rw-rw----',0,''),(11,'Entry','entry','',1,1,'rw-r--r--',0,''),(12,'Search','search','',1,1,'rw-r--r--',0,''),(14,'Tool','tool','',1,2,'rw-rw----',0,''),(15,'Advanced search','advancedsearch','',1,1,'rw-r--r--',0,''),(16,'Profile','profile','user',1,2,'rw-rw----',6,'manage'),(17,'Groups','managegroups','users',1,1,'rw-------',5,'manage'),(18,'Bulkedit','bulkedit','',1,2,'rw-rw----',0,''),(19,'System Information','sysinfo','info',1,1,'rw-------',3,'show');
/*!40000 ALTER TABLE `#REPLACEME#_menu` ENABLE KEYS */;
UNLOCK TABLES;
* limitations under the License.
*/
+/**
+ * A plain and simple setup for bibliotheca
+ * It creates the config file based on the .default file.
+ * It creates the default database tables.
+ * It self deletes after a setup is complete to reduce some sercuirty risks
+ */
+
mb_http_output('UTF-8');
mb_internal_encoding('UTF-8');
ini_set('error_reporting',-1); // E_ALL & E_STRICT
if(!is_dir('../systemout') || !is_writeable('../systemout')) {
die('Missing correct write permissions for ../systemout dir');
}
+if(!is_writeable(getcwd())) {
+ die('Missing correct write/delete permissions for the setup folder');
+}
$configStep = 'ready';
$configFile = '../config/config.php';
$DB->query("SET collation_connection = 'utf8mb4_unicode_ci'");
}
-
if(!empty($_conCheck)) {
try {
$query = $DB->query("SELECT * FROM information_schema.tables WHERE table_schema = '".DB_NAME."' AND table_name = '".DB_PREFIX."_sys_fields' LIMIT 1");
--- /dev/null
+<h3 class="uk-h3">System information</h3>
+<div class="uk-grid-small uk-grid-row-small" uk-grid>
+ <div class="uk-width-1-2">
+ <div class="uk-grid-divider uk-child-width-expand@s" uk-grid>
+ <?php foreach($TemplateData['existingCollections'] as $k=>$v) { ?>
+ <div>
+ <p>
+ <b><?php echo $v['name']; ?></b><br/>
+ <?php echo $v['description']; ?>
+ </p>
+ <p>
+ Created: <code><?php echo $v['created']; ?></code></code><br />
+ Entries: <code><?php echo $v['stats']['entriesCount']; ?></code><br />
+ Tags: <code><?php echo $v['stats']['tagsCount']; ?></code><br />
+ DB Usage: <code><?php echo $v['stats']['tableSize']; ?></code><br />
+ Disk Usage: <code><?php echo $v['stats']['storageSize']; ?></code>
+ </p>
+ </div>
+ <?php } ?>
+ </div>
+ </div>
+ <div class="uk-width-1-2">
+ <ul>
+ <li>Bibliotheca: <code><?php echo $TemplateData['bibVersion']; ?></code></li>
+ <li>Apache (depends on ServerTokens setting): <code><?php echo $TemplateData['apacheVersion']; ?></code></li>
+ <li>PHP: <code><?php echo $TemplateData['phpVersion']; ?></code></li>
+ <li>MySQL server: <code><?php echo $TemplateData['mysqlVersion']; ?></code></li>
+ <li>MySQL data usage: <code><?php echo $TemplateData['overallTableSize']; ?></code>MB</li>
+ <li>Storage usage: <code><?php echo $TemplateData['overallStorageSize']; ?></code></li>
+ </ul>
+ </div>
+</div>
--- /dev/null
+<?php
+/**
+* Bibliotheca
+*
+* Copyright 2018-2020 Johannes Keßler
+*
+* 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.
+*/
+
+$TemplateData['bibVersion'] = BIB_VERSION;
+$TemplateData['apacheVersion'] = apache_get_version();
+$TemplateData['phpVersion'] = phpversion();
+$TemplateData['mysqlVersion'] = mysqli_get_server_info($DB);
+
+$overallTableSize = 0; // MB
+$queryStr = "SELECT (DATA_LENGTH + INDEX_LENGTH) AS `size`
+ FROM information_schema.TABLES
+ WHERE TABLE_SCHEMA = 'bibliotheca'
+ ORDER BY (DATA_LENGTH + INDEX_LENGTH) DESC";
+if(QUERY_DEBUG) error_log("[QUERY] ".__METHOD__." query: ".var_export($queryStr,true));
+try {
+ $query = $DB->query($queryStr);
+ if($query !== false && $query->num_rows > 0) {
+ while(($result = $query->fetch_assoc()) != false) {
+ $overallTableSize += $result['size'];
+ }
+ }
+}
+catch (Exception $e) {
+ error_log("[ERROR] ".__METHOD__." mysql catch: ".$e->getMessage());
+}
+$TemplateData['overallTableSize'] = Summoner::bytesToHuman($overallTableSize);
+
+$TemplateData['overallStorageSize'] = Summoner::bytesToHuman(Summoner::folderSize(PATH_STORAGE));
+
+require_once 'lib/trite.class.php';
+$Trite = new Trite($DB,$Doomguy);
+$TemplateData['existingCollections'] = $Trite->getCollections("write");
+foreach($TemplateData['existingCollections'] as $k=>$v) {
+ $Trite->load($k);
+ $TemplateData['existingCollections'][$k] = $Trite->getStats();
+}
.input-multiple-template {
margin: 1px;
}
+
+.uk-navbar-dropdown {
+ width: auto;
+}