feat: add videodb media index with Docker stack

- Add videodb PHP/MySQL media collection manager (Blu-ray, DVD, CD)
- Dockerfile: PHP 8.1 + Apache with GD/mysqli/exif extensions
- docker-compose.yml: app on port 6761 + MySQL 8.0 with health checks
- docker-entrypoint.sh: auto-generates config.inc.php from env vars,
  waits for MySQL, initializes DB schema idempotently
- init-db.php: CLI schema installer using app's own prefix_query() logic
- Persistent volumes for DB, cache, and cover images

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-11 09:49:52 +02:00
commit f55c91276e
1230 changed files with 252321 additions and 0 deletions

View File

@@ -0,0 +1,56 @@
<?php
/**
* VariableStream class
*
* @package Core
* @author Andreas Goetz <cpuidle@gmx.de>
* @version $Id: VariableStream.class.php,v 1.4 2004/10/30 11:48:36 andig2 Exp $
*/
// stream wrappers require php > 4.3
if (version_compare(phpversion(), '4.3') < 0)
{
errorpage('PHP version mismatch',
'At least PHP version 4.3.0 is required to run the VariableStream, please check the documentation!');
}
/**
* VariableStream allows XML reading from variables
* @package Core
*/
class VariableStream
{
var $position;
var $varname;
var $context;
function stream_open($path, $mode, $options, &$opened_path) {
$url = parse_url($path);
$this->varname = $url['host'];
$this->position = 0;
return true;
}
function stream_read($count) {
$ret = substr($GLOBALS[$this->varname], $this->position, $count);
$this->position += strlen($ret);
return $ret;
}
function stream_eof() {
return $this->position >= strlen($GLOBALS[$this->varname]);
}
function stream_stat() {
return array('size' => strlen($GLOBALS[$this->varname]));
}
function url_stat() {
return array();
}
}
// register stream type to allow use in xml->load
stream_wrapper_register('var', 'VariableStream');
?>

196
videodb/core/cache.php Normal file
View File

@@ -0,0 +1,196 @@
<?php
/**
* File caching functions
*
* @package Core
* @author Andreas Goetz <cpuidle@gmx.de>
* @version $Id: cache.php,v 1.11 2013/04/26 15:09:35 andig2 Exp $
*/
// define cache folder
if (!defined('CACHE')) define('CACHE', 'cache');
/**
* Get the hashed filename
*
* @param string url of the item
* @param string $cache_folder name ob the sub-cache to adress
* @param string ext file extension of the cache file
*/
function cache_get_filename($url, $cache_folder, $ext = '')
{
$hash = md5($url) . (($ext) ? '.'.$ext : '');
$cache_file = cache_get_folder($cache_folder, $hash) . $hash;
return $cache_file;
}
/**
* Get name of the cache folder
*
* @TODO decouple from global config options
*
* @param string $cache_folder name ob the sub-cache to adress
* @param string $cache_filename name of the item to be cached for use with hierarchical caches
* @return string cache folder path including trailing /
*/
function cache_get_folder($cache_folder, $cache_filename = '')
{
global $config;
$cache_folder = CACHE.'/' .
(($cache_folder) ? $cache_folder.'/' : '');
if ($cache_filename)
$cache_folder .= substr($cache_filename, 0, @(int)$config['hierarchical']).'/';
return $cache_folder;
}
/**
* Cleanup a single cache folder
*
* @param string $cache_folder path to cache folder
* @param int $cache_max_age maximum age of cached items in seconds
* @param bool $force_prune force cache pruning even if not due according to schedule
*/
function cache_prune_folder($cache_folder, $cache_max_age, $force_prune = false, $simulate = false, $pattern = '*')
{
if (!preg_match('#/$#', $cache_folder)) $cache_folder .= '/';
$stamp = $cache_folder.'cache_last_purge';
$cache_mtime = @filemtime($stamp); // get time the cache was last purged (once a day)
// if cache was last purged a day or more ago
if ($force_prune || ((time() - $cache_mtime) > ($cache_max_age / 24))) # 86400)
{
foreach (glob($cache_folder.$pattern, GLOB_NOSORT) as $file)
{
// avoid hidden files and directories
if (is_file($file) &! preg_match("/^\./", $file) && time() - filemtime($file) > $cache_max_age)
{
if ($simulate)
$files[] = $file; // add to list of potentially purged files
else
@unlink($file); // purge cache
}
}
if ($simulate) return $files;
@touch($stamp); // mark purge as having occurred
return true;
}
return false;
}
/**
* Cleanup a cache folder hierarchy
*
* @TODO decouple from global config options
*
* @param string $cache_folder path to cache folder
* @param int $cache_max_age maximum age of cached items in seconds
* @param bool $force_prune force cache pruning even if not due according to schedule
*/
function cache_prune_folders($cache_folder, $cache_max_age, $force_prune = false, $simulate = false, $pattern = '*', $levels = 0)
{
global $config;
// root folder
cache_prune_folder($cache_folder, $cache_max_age, $force_prune, $simulate, $pattern, $levels);
// descent hierarchy
if ($levels > 0)
{
if (!isset($error))
{
$error = '';
}
for ($i=0; $i<16; $i++)
$error .= cache_prune_folders($cache_folder.dechex($i).'/', $cache_max_age, $force_prune, $simulate, $pattern, $levels-1);
}
}
/**
* Create cache folders
*
* Check individual cache folder for existance, check if folder is writable and create folder if it doesn't exist
*/
function cache_create_folders($dir, $levels = 0)
{
$error = '';
if (!is_dir($dir))
{
if (!@mkdir($dir, 0700)) $error = 'Directory <code>'.$dir.'</code> does not exist.<br/>';
}
elseif (!is_writable($dir))
{
$error = 'Directory <code>'.$dir.'</code> is not writable.<br/>';
}
// check hierarchical folders
if (empty($error) && ($levels > 0))
{
for ($i=0; $i<16; $i++)
$error .= cache_create_folders($dir.'/'.dechex($i), $levels-1);
}
return $error;
}
/**
* Verify existance of cached file for given url/ extension
*
* @author Andreas Goetz <cpuidle@gmx.de>
* @param string url of the item
* @param string ext file extension of the cache file
* @param string file result: URL to the cached image if exists
* @return bool result of check
*/
function cache_file_exists($url, &$cache_file, $cache_folder, $ext = '')
{
$cache_file = cache_get_filename($url, $cache_folder, $ext);
// Small performance fix
$result = file_exists($cache_file) && filesize($cache_file);
# $result = filesize($cache_file) > 0;
return($result);
}
function cache_get($url, $cache_folder, $cache_max_age, $serialize = false)
{
$data = false;
if ($cache_max_age > 0)
{
if (cache_file_exists($url, $cache_file, $cache_folder))
{
if (time() - filemtime($cache_file) < $cache_max_age)
{
$data = file_get_contents($cache_file);
if (($data !== false) && $serialize) $data = unserialize($data);
}
// TODO Check if outdated cache files should really be auto-deleted
else @unlink($cache_file);
}
}
return $data;
}
function cache_put($url, $data, $cache_folder, $cache_max_age, $serialize = false)
{
// only put file to cache if caching is enabled
if ($cache_max_age > 0)
{
// get the cache file name
$cache_file = cache_get_filename($url, $cache_folder);
// commit to disk
if ($serialize) $data = serialize($data);
file_put_contents($cache_file, $data);
}
}
?>

View File

@@ -0,0 +1,312 @@
<?php
/**
* Compatibility functions
*
* Borrowed simplified functions from PEAR module PHP_Compat
*
* @package Core
* @author Andreas Goetz <cpuidle@gmx.de>
* @link http://pear.php.net PEAR
* @version $Id: compatibility.php,v 1.15 2013/03/13 16:38:19 andig2 Exp $
*/
/**
* Implements file_get_contents introduced in v4.3.0
*/
if (!function_exists('file_get_contents'))
{
function file_get_contents($filename)
{
$fh = @fopen($filename, 'rb');
if (!$fh) return false;
$content = fread($fh, filesize($filename));
fclose($fh);
return $content;
}
}
/**
* Implements file_put_contents introduced in v5.0.0
*/
if (!function_exists('file_put_contents'))
{
function file_put_contents($filename, $content)
{
$fh = @fopen($filename, 'wb');
if (!$fh) return false;
if (!fwrite($fh, $content, strlen($content))) return false;
fclose($fh);
return true;
}
}
/**
* Implements html_entity_decode introduced in v4.3.0
* @author <martin@swertcw.com>
* @param string $string HTML encoded string
* @return string HTML decoded string
*/
if (!function_exists('html_entity_decode'))
{
function html_entity_decode($string)
{
// replace numeric entities
$string = preg_replace('~&#x([0-9a-f]+);~ei', 'chr(hexdec("\\1"))', $string);
$string = preg_replace('~&#([0-9]+);~e', 'chr(\\1)', $string);
// replace literal entities
$trans_tbl = get_html_translation_table(HTML_ENTITIES);
$trans_tbl = array_flip($trans_tbl);
return strtr($string, $trans_tbl);
}
}
/**
* Implements http_build_query introduced in v5.0.0
*/
if (!function_exists('http_build_query'))
{
function http_build_query ($formdata, $numeric_prefix = null)
{
// Check we have an array to work with
if (!is_array($formdata)) {
return $formdata;
}
// Start building the query
$tmp = array ();
foreach ($formdata as $key => $val)
{
array_push($tmp, urlencode($key).'='.urlencode($val));
}
return implode('&', $tmp);
}
}
/**
* Multibyte-aware character case conversion
*
* @author tedemo <tedemo@free.fr>
*/
if (!function_exists('mb_convert_case'))
{
function mb_convert_case($str)
{
return ucwords(strtolower($str));
}
}
/**
* iconv alternatives
*
* @author Andreas Goetz <cpuidle@gmx.de>
*/
if (!function_exists('iconv'))
{
function iconv($source_encoding, $target_encoding, $str)
{
// remove transliteration- only available in native iconv
$source_encoding = preg_replace('#^(.+?)(//.*)#', '\\1', $source_encoding);
$target_encoding = preg_replace('#^(.+?)(//.*)#', '\\1', $target_encoding);
if (function_exists('mb_convert_encoding'))
return mb_convert_encoding($str, $target_encoding, $source_encoding);
elseif (function_exists('recode_string'))
return recode_string($source_encoding.'..'.$target_encoding, $str);
else
return $str;
}
}
/**
* Implements json_encode introduced in v5.2.0
*
* @author Andreas Goetz <cpuidle@gmx.de>
*/
if (!function_exists('json_encode'))
{
function json_encode($data)
{
require_once('./lib/json.php');
$json = new Services_JSON();
return($json->encode($data));
}
}
/**
* Implements json_decode introduced in v5.2.0
*
* @author Andreas Goetz <cpuidle@gmx.de>
*/
if (!function_exists('json_decode'))
{
function json_decode($data)
{
require_once('./lib/json.php');
$json = new Services_JSON();
return($json->decode($data));
}
}
/**
* Implements json_decode introduced in v5.0.0
*
* @author Andreas Goetz <cpuidle@gmx.de>
*/
if (!function_exists('http_build_query'))
{
function http_build_query($formdata, $numeric_prefix = null, $key = null)
{
$res = array();
foreach ((array)$formdata as $k=>$v)
{
$tmp_key = urlencode(is_int($k) ? $numeric_prefix.$k : $k);
if ($key) $tmp_key = $key.'['.$tmp_key.']';
if ( is_array($v) || is_object($v) ) {
$res[] = http_build_query($v, null /* or $numeric_prefix if you want to add numeric_prefix to all indexes in array*/, $tmp_key);
} else {
$res[] = $tmp_key."=".urlencode($v);
}
}
$separator = ini_get('arg_separator.output');
return implode($separator, $res);
}
}
/**
* Quick image type detection
*
* @author Andreas Goetz <cpuidle@gmx.de>
*/
if (!function_exists('exif_imagetype'))
{
function exif_imagetype($filename)
{
if ((list($width, $height, $type, $attr) = getimagesize($filename )) !== false ) {
return $type;
}
return false;
}
}
/**
* Ease PHP 5.3.0 requirement on Windows
*
* @author Andreas Goetz <cpuidle@gmx.de>
*/
if (!function_exists('linkinfo'))
{
function linkinfo($path)
{
return 0;
}
}
/**
* Polyfill for PHP 4 - PHP 7
* introduced in PHP 8
*/
if (!function_exists('str_contains'))
{
function str_contains(string $haystack, string $needle): bool
{
return strpos($haystack, $needle) !== false;
}
}
/**
* This file is part of the array_column library
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* @copyright Copyright (c) 2013 Ben Ramsey <http://benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
*/
/**
* Returns the values from a single column of the input array, identified by
* the $columnKey.
*
* Optionally, you may provide an $indexKey to index the values in the returned
* array by the values from the $indexKey column in the input array.
*
* @param array $input A multi-dimensional array (record set) from which to pull
* a column of values.
* @param mixed $columnKey The column of values to return. This value may be the
* integer key of the column you wish to retrieve, or it
* may be the string key name for an associative array.
* @param mixed $indexKey (Optional.) The column to use as the index/keys for
* the returned array. This value may be the integer key
* of the column, or it may be the string key name.
* @return array
*/
if (!function_exists('array_column'))
{
function array_column($input = null, $columnKey = null, $indexKey = null)
{
// Using func_get_args() in order to check for proper number of
// parameters and trigger errors exactly as the built-in array_column()
// does in PHP 5.5.
$params = func_get_args();
if (!isset($params[0])) {
trigger_error('array_column() expects at least 2 parameters, 0 given', E_USER_WARNING);
return null;
} elseif (!isset($params[1])) {
trigger_error('array_column() expects at least 2 parameters, 1 given', E_USER_WARNING);
return null;
}
if (!is_array($params[0])) {
trigger_error('array_column() expects parameter 1 to be array, ' . gettype($params[0]) . ' given', E_USER_WARNING);
return null;
}
if (!is_int($params[1])
&& !is_string($params[1])
&& !(is_object($params[1]) && method_exists($params[1], '__toString'))
) {
trigger_error('array_column(): The column key should be either a string or an integer', E_USER_WARNING);
return false;
}
if (isset($params[2])
&& !is_int($params[2])
&& !is_string($params[2])
&& !(is_object($params[2]) && method_exists($params[2], '__toString'))
) {
trigger_error('array_column(): The index key should be either a string or an integer', E_USER_WARNING);
return false;
}
$paramsInput = $params[0];
$paramsColumnKey = (string) $params[1];
$paramsIndexKey = (isset($params[2]) ? (string) $params[2] : null);
$resultArray = array();
foreach ($paramsInput as $row) {
$key = $value = null;
$keySet = $valueSet = false;
if ($paramsIndexKey !== null && array_key_exists($paramsIndexKey, $row)) {
$keySet = true;
$key = $row[$paramsIndexKey];
}
if (is_array($row) && array_key_exists($paramsColumnKey, $row)) {
$valueSet = true;
$value = $row[$paramsColumnKey];
}
if ($valueSet) {
if ($keySet) {
$resultArray[$key] = $value;
} else {
$resultArray[] = $value;
}
}
}
return $resultArray;
}
}
?>

View File

@@ -0,0 +1,76 @@
<?php
/**
* Constants
*
* Contains global constants for table names
* Must only be loaded after config.inc.php
*
* @package Core
* @author Andreas Goetz <cpuidle@gmx.de>
* @version $Id: constants.php,v 1.65 2013/04/25 15:00:32 andig2 Exp $
*/
// Config file
define('CONFIG_FILE', './config.inc.php');
define('VERSION', '4.1.0');
define('LOG_FILE', 'debug.log');
// User Permission bit masks
define('PERM_ADMIN', 1);
define('PERM_READ', 2);
define('PERM_WRITE', 4);
define('PERM_ADULT', 8);
define('PERM_ALL', -1); // used to check for "all" permissions only
define('PERM_ANY', -2); // used to check for exististance of any cross-user permission
// Cache folders
define('CACHE_IMG', 'img');
define('CACHE_HTML', 'imdb');
define('CACHE_THUMBS', 'thumbs');
define('CACHE_LOCAL', 'local'); // local images for covers and actors
// Table names
define('TBL_DATA', $config['db_prefix'].'videodata');
define('TBL_CONFIG', $config['db_prefix'].'config');
define('TBL_USERCONFIG', $config['db_prefix'].'userconfig');
define('TBL_USERS', $config['db_prefix'].'users');
define('TBL_USERSEEN', $config['db_prefix'].'userseen');
define('TBL_PERMISSIONS', $config['db_prefix'].'permissions');
define('TBL_ACTORS', $config['db_prefix'].'actors');
define('TBL_GENRES', $config['db_prefix'].'genres');
define('TBL_VIDEOGENRE', $config['db_prefix'].'videogenre');
define('TBL_MEDIATYPES', $config['db_prefix'].'mediatypes');
define('TBL_LENT', $config['db_prefix'].'lent');
define('TBL_CACHE', $config['db_prefix'].'cache');
// Wishlist
define('MEDIA_WISHLIST', 50);
// Amazon associates token
define('AMAZON_ASSOCIATE', 'cpuidle-20');
// Database character set - only valid values are UTF8, LATIN1 (legacy only) or empty
define('DB_CHARSET', 'UTF8');
// Database sort order - if empty sorting is defined by language file or db standard.
// use UTF8_GENERAL_CI or other valid MySQL collation to override
define('DB_COLLATION', '');
// Required database version
define('DB_REQUIRED', 41);
/**
* These used to be defined inside config.sample and therefore config.inc
* Removed the need for them inside config.* but since their definition can still
* be inside config.inc prefixed here with a check
*/
if (!defined('TUMB_NO_SCALE')) define('TUMB_NO_SCALE', -1); // no scaling - use of thumbnails is disabled
if (!defined('TUMB_REDUCE_ONLY')) define('TUMB_REDUCE_ONLY', 0); // reduce only - create thumbnails when requested image dimensions are smaller than original image
if (!defined('TUMB_SCALE')) define('TUMB_SCALE', 1); // always scale - create thumbnails for all images (applies aliasing when scaling)

492
videodb/core/custom.php Normal file
View File

@@ -0,0 +1,492 @@
<?php
/**
* Custom handlers
*
* Defines functions for displaying custom fields.
* To add your own type define input and output functions for it here. These
* functions will be called in show.php (output) and edit.php (input). You can
* get other values from these files by global'ing them into your function. See
* ed2k as an example.
*
* @todo Check if this can be moved to Smarty plugins
*
* @package Custom
* @author Andreas Gohr <a.gohr@web.de>
* @version $Id: custom.php,v 1.16 2008/10/03 14:18:04 andig2 Exp $
*/
/*
Hint:
$cn
holds the name of the custom field (eg. 'custom2') use this as the name for
the input formfield
$cv
holds the current value of that field if any. When you want to use it as
value in a formfield quote it with the formvar() function!
When you add new types send them to me. I will include them here.
*/
///////////////////////////////////////////////////////////////////////////////
/* This array contains all available types - be sure to add your type if
you ad a new one */
$allcustomtypes=array('',
'text',
'url',
'ed2k',
'language',
'orgtitle',
'movix',
'mpaa',
'bbfc',
'fsk',
'barcode',
'kijkwijzer'
);
/**
* Assigns custom field names and values to input object
* @author Andreas Goetz <cpuidle@gmx.de>
* @param hashref $video Reference to video hash structure
* @param string $inout Either in or out, determines type of control
* returned (html input control or rendered output)
*/
function customfields(&$video, $inout)
{
global $config;
$inout_function = ($inout == 'in') ? '_input' : '_output';
for ($i=1; $i < 5; $i++)
{
if (!empty($config['custom'.$i]))
{
$video['custom'.$i.'name'] = $config['custom'.$i];
$run = 'custom_'.$config['custom'.$i.'type'].$inout_function;
$custom_value = null;
if (array_key_exists('custom'.$i, $video))
{
$custom_value = $video['custom'.$i];
}
$video['custom'.$i.$inout] = $run('custom'.$i,$custom_value);
}
}
}
/**
* Custom Type:
*
* Standardinputhandler for custom fields -> just calls text type
*/
function custom__input($cn,$cv)
{
return custom_text_input($cn,$cv);
}
/**
* Custom Type:
*
* Standardoutputhandler for custom fields -> just calls text type
*/
function custom__output($cn,$cv)
{
return custom_text_output($cn,$cv);
}
/**
* Custom Type: text
*
* Standardinputhandler for custom fields
*/
function custom_text_input($cn,$cv)
{
return '<input type="text" size="45" maxlength="255" name="'.$cn.'" id="'.$cn.'" value="'.formvar($cv).'" />';
}
/**
* Custom Type: text
*
* Standardouputhandler for custom fields
*/
function custom_text_output($cn,$cv)
{
return $cv;
}
/**
* Custom Type: url
*
* Stores an URL in a custom file and shows a clickable link.
*/
function custom_url_input($cn,$cv)
{
return '<input type="text" size="45" maxlength="255" name="'.$cn.'" id="'.$cn.'" value="'.formvar($cv).'" />';
}
/**
* Custom Type: url
*
* Stores an URL in a custom file and shows a clickable link.
*/
function custom_url_output($cn,$cv)
{
if (!empty($cv))
{
return '<a href="'.$cv.'">[ Link ]</a>';
} else {
return '';
}
}
/**
* Custom Type: ed2k
*
* Stores the MD4 sum of the File in a custom file and shows a clickable ed2k
* Link for the eDonkey2000 client tools.
*/
function custom_ed2k_input($cn,$cv)
{
return '<input type="text" size="40" maxlength="255" name="'.$cn.'" id="'.$cn.'" value="'.formvar($cv).'" /> (MD4)';
}
/**
* Custom Type: ed2k
*
* Stores the MD4 sum of the File in a custom file and shows a clickable ed2k
* Link for the eDonkey2000 client tools.
*/
function custom_ed2k_output($cn,$cv)
{
global $video;
if (!empty($video[0]['filesize']) && !empty($video[0]['filename']) && !empty($cv)) {
return '<a href="ed2k://|file|'.$video[0]['filename'].'|'.$video[0]['filesize'].'|'.$cv.'|">[ Add to eDonkey ]</a>';
} else {
return '';
}
}
/**
* Custom Type: language
*
* Language Selection with Quickselectionbuttons configured in
* $config['languages']
*/
function custom_language_input($cn,$cv)
{
global $config;
$output = '';
$output .= '<input type="text" size="15" maxlength="255" name="'.$cn.'" id="'.$cn.'" value="'.formvar($cv).'" /> ';
foreach ($config['languages'] as $flag)
{
$output .= '<a href="#" title="set to '.$flag.'" onclick="document.edi.'.$cn.'.value=\''.$flag.'\'">';
$output .= '<img src="'.img('flags/'.$flag.'.gif').'" border="0" alt="'.formvar($cv).'" /></a> ';
}
return $output;
}
/**
* Custom Type: language
*
* Language Selection with Quickselectionbuttons configured in
* $config[languages]
*/
function custom_language_output($cn,$cv)
{
return custom_text_output($cn,$cv);
}
/**
* Custom Type: FSK
*
* Allows you to set the FSK Rating of a movie.
*
* @author Chinamann <chinamann@users.sourceforge.net>
*/
function custom_fsk_input($cn,$cv)
{
return custom_text_input($cn,$cv);
}
/**
* Custom Type: FSK
*
* Allows you to display the FSK Rating.
*
* @author Chinamann <chinamann@users.sourceforge.net>
*/
function custom_fsk_output($cn,$cv)
{
$allfsktypes = array('0','6','12','16','18');
if (!in_array ($cv, $allfsktypes))
{
return custom_text_output($cn,$cv);
}
return '<a href="search.php?q='.$cv.'&fields='.$cn.'"><img border="0" src="'.img('r_'.$cv.'.gif').'" width="50" height="50" /></a>';
}
/**
* Custom Type: Barcode
*
* Allows you to input the Barcode of a movie.
*
* @author Chinamann <chinamann@users.sourceforge.net>
*/
function custom_barcode_input($cn,$cv)
{
return custom_text_input($cn,$cv);
}
/**
* Custom Type: Barcode
*
* Allows you to display Barcode.
*
* @author Chinamann <chinamann@users.sourceforge.net>
*/
function custom_barcode_output($cn,$cv)
{
return custom_text_output($cn,$cv);
}
/**
* Custom Type: Originaltitle
*
* Holds the Original title of an movie
*
* @author Stephan Zalewski <stephan-01@gmx.de>
*/
function custom_orgtitle_input($cn,$cv)
{
global $config;
global $imdbdata;
global $id;
if (empty($cv)|| $config['lookupdefault_edit'] > 0 || $config['lookupdefault_new'] > 0)
{
if (!empty($imdbdata['title'])) {$cv .= ' - '.$imdbdata['title'];}
if (!empty($imdbdata['subtitle'])) {$cv .= ' - '.$imdbdata['subtitle'];}
// we need to save our self here!
if (!empty($id) && $cv != '')
{
$qcv = escapeSQL($cv);
$UPDATE = "UPDATE ".TBL_DATA." SET $cn = '$qcv' WHERE id = $id";
runSQL($UPDATE);
}
}
return custom_text_input($cn,$cv);
}
/**
* Custom Type: Originaltitle
*
* Holds the Original title of an movie
*
* @author Stephan Zalewski <stephan-01@gmx.de>
*/
function custom_orgtitle_output($cn,$cv)
{
return custom_text_output($cn,$cv);
}
/**
* Custom Type: Movix
*
* Allows you to indicate if a movie is stored in a cd/dvd
* with movix (http://movix.sourceforge.net/)
*
* @author Antonio Giungato <antonio_giungato@libero.it>
*/
function custom_movix_input($cn,$cv)
{
$output ='<select name="'.$cn.'">
<option selected value=""></option>
<option value="eMovix">eMovix</option>
<option value="Movix">Movix</option>
<option value="Movix²">Movix²</option>
</select>';
return $output;
}
function custom_movix_output($cn,$cv)
{
return custom_text_output($cn,$cv);
}
/**
* Custom Type: MPAA
*
* Show the MPAA rating of a movie
*
* @author Tim M. Sanders <tsanders@thesanders.org>
*/
function custom_mpaa_input($cn,$cv)
{
global $config;
global $imdbdata;
global $id;
if (empty($cv)|| $config['lookupdefault_edit'] > 0 || $config['lookupdefault_new'] > 0)
{
if (!empty($imdbdata['mpaa'])) {$cv .= $imdbdata['mpaa'];}
//we need to save our self here!
if(!empty($id) && $cv != '')
{
$qcv = escapeSQL($cv);
$UPDATE = "UPDATE ".TBL_DATA." SET $cn = '$qcv' WHERE id = $id";
runSQL($UPDATE);
}
}
$output = '<input type="text" size="50" maxlength="255" name="'.$cn.'" id="'.$cn.'" value="'.formvar($cv).'" /> ';
return $output;
}
/**
* Custom Type: MPAA
*
* Show the MPAA rating of a movie
*
* @author Tim M. Sanders <tsanders@thesanders.org>
*/
function custom_mpaa_output($cn,$cv)
{
global $imdbdata;
global $id;
$ratings = array('R' => 'mpaa-R.gif',
'NC-17' => 'mpaa-NC-17.gif',
'PG-13' => 'mpaa-PG-13.gif',
'PG' => 'mpaa-PG.gif',
'G' => 'mpaa-G.gif');
$output = custom_text_output($cn,$cv);
foreach ($ratings as $rating => $image)
{
if (strstr($output, $rating))
{
$output .= '<br/><img src="'.img($image).'" alt="'.$rating.'"/>';
break;
}
}
return $output;
}
/**
* Custom Type: BBFC
*
* Show the BBFC rating of a movie
* Based on the MPAA ratings above
*
* @author Colin Ogilvie <csogilvie@users.sourceforge.net>
*/
function custom_bbfc_input($cn,$cv)
{
global $config;
global $imdbdata;
global $id;
if (empty($cv)|| $config['lookupdefault_edit'] > 0 || $config['lookupdefault_new'] > 0)
{
$cv = $imdbdata['bbfc'];
if (!empty($imdbdata['bbfc'])) $cv .= $imdbdata['bbfc'];
//we need to save our self here!
if(!empty($id) && $cv != '')
{
$qcv = escapeSQL($cv);
$UPDATE = "UPDATE ".TBL_DATA." SET $cn = '$qcv' WHERE id = $id";
runSQL($UPDATE);
}
}
$output = '<input type="text" size="10" maxlength="4" name="'.$cn.'" id="'.$cn.'" value="'.formvar($cv).'" />';
$output .= " <a href='#' onclick='document.edi.".$cn.".value=\"U\"'>U</a>";
$output .= " <a href='#' onclick='document.edi.".$cn.".value=\"12\"'>12</a>";
$output .= " <a href='#' onclick='document.edi.".$cn.".value=\"12A\"'>12A</a>";
$output .= " <a href='#' onclick='document.edi.".$cn.".value=\"15\"'>15</a>";
$output .= " <a href='#' onclick='document.edi.".$cn.".value=\"18\"'>18</a>";
$output .= " <a href='#' onclick='document.edi.".$cn.".value=\"PG\"'>PG</a>";
return $output;
}
/**
* Custom Type: BBFC
*
* Show the BBFC rating of a movie
* Based on the MPAA ratings above
*
* @author Colin Ogilvie <csogilvie@users.sourceforge.net>
*/
function custom_bbfc_output($cn,$cv)
{
global $imdbdata;
global $id;
$ratings = array('PG' => 'bbfc-PG.gif',
'12A' => 'bbfc-12A.gif',
'12' => 'bbfc-12.gif',
'15' => 'bbfc-15.gif',
'18' => 'bbfc-18.gif',
'U' => 'bbfc-U.gif');
$output = custom_text_output($cn,$cv);
foreach ($ratings as $rating => $image)
{
if (strstr($output, (string) $rating))
{
$output = '<img src="'.img($image).'" alt="'.$rating.'"/>';
break;
}
}
return $output;
}
function custom_kijkwijzer_kijkwijzerdata () {
return [
'AL' => [1, 'Alle leeftijden', 'kijkwijzer/al.png', ''],
'06' => [2, '6 jaar', 'kijkwijzer/6.png', ''],
'09' => [4, '9 jaar', 'kijkwijzer/9.png', ''],
'12' => [8, '12 jaar', 'kijkwijzer/12.png', ''],
'14' => [16, '14 jaar', 'kijkwijzer/14.png', ''],
'16' => [32, '16 jaar', 'kijkwijzer/16.png', ''],
'18' => [64, '18 jaar', 'kijkwijzer/18.png', ''],
'AN' => [128, 'Angst', 'kijkwijzer/angst.png', ''],
'DI' => [256, 'Discriminatie', 'kijkwijzer/discriminatie.png', ''],
'DA' => [512, 'Roken, alcohol en drugs', 'kijkwijzer/drugs-en-alcohol.png', ''],
'GE' => [1024, 'Geweld', 'kijkwijzer/geweld.png', ''],
'SE' => [2048, 'Seks', 'kijkwijzer/seks.png', ''],
'TA' => [4096, 'Grof taalgebruik', 'kijkwijzer/taal.png', '']
];
}
function custom_kijkwijzer_input ($cn, $cv) {
$kijkwijzer = custom_kijkwijzer_kijkwijzerdata();
$output = '<input type="text" size="10" maxlength="4" name="'.$cn.'" id="'.$cn.'" value="'.formvar($cv).'" />';
foreach ($kijkwijzer as $val => $cfg) {
$output .= " <a href='#' onclick='document.edi.".$cn.".value+=\"".$val." \"' title='".$cfg[1]."'><img src=\"".img($cfg[2])."\" alt=\"Kijkwijzer: ".$cfg[1]."\" data-desc=\"".$cfg[3]."\" width=\"32\" /></a>";
}
return $output;
}
function custom_kijkwijzer_output ($cn, $cv, $sm = false) {
$kijkwijzer = custom_kijkwijzer_kijkwijzerdata();
$rv = '';
$cv = explode(' ', trim($cv));
foreach ($cv as $i) {
if (isset($kijkwijzer[$i])) {
$rv .= '<img src="' . img($kijkwijzer[$i][2]) . '" alt="Kijkwijzer: ' . $kijkwijzer[$i][1] . '" title="' . $kijkwijzer[$i][1] . '" width="' . ($sm ? 24 : 48) . '" />';
}
}
return $rv;
}

263
videodb/core/edit.core.php Normal file
View File

@@ -0,0 +1,263 @@
<?php
/**
* Edit functions. Split into separate file for reuse.
*
* @package videoDB
* @author Andreas Götz <cpuidle@gmx.de>
* @author Andreas Gohr <a.gohr@web.de>
* @author Chinamann <chinamann@users.sourceforge.net>
* @version $Id: edit.core.php,v 1.9 2009/12/05 13:56:04 andig2 Exp $
*/
require_once './core/security.php';
// list of fields to be read/written from/to html form
$imdb_set_fields = array('md5','title','subtitle','language','diskid','mediatype','comment','disklabel',
'imdbID','year','imgurl','director','actors','runtime','country','plot','filename',
'filesize','filedate','audio_codec','video_codec','video_width','video_height','istv',
'rating', 'custom1','custom2','custom3','custom4');
// list of fields to be overwritten by refetchAllInfos-Script
$imdb_overwrite_fields = array('comment','disklabel','imdbID','year','director','actors','runtime','country','plot',
'rating','custom1','custom2','custom3','custom4');
// special fields for SQL statements
$db_null_fields = array('runtime', 'filesize', 'filedate', 'video_width', 'video_height');
$db_zero_fields = array('istv', 'year');
/**
* Obtain new disk id
*
* @return string Generated disk id
*/
function getDiskId()
{
global $config;
/*
* change this if you have some fancy naming style
*/
// how many digits have to be used for DiskId?
$digits = ($config['diskid_digits']) ? $config['diskid_digits'] : 4;
/*
* Old way automatic DiskID was generated: result was "highest ID + 1"
*
$NEXTUSERID = "SELECT LPAD(TRIM(LEADING '0' FROM MAX(LPAD(TRIM(LEADING '0' FROM diskid), 10, '0'))) + 1, ".
$digits.", '0') AS max FROM ".TBL_DATA.' WHERE diskid NOT REGEXP "[^0-9]"';
$result = runSQL($NEXTUSERID);
return $result[0]['max'];
*/
// get all DiskIds ordered from DB
$SQL = "SELECT LPAD(TRIM(LEADING '0' FROM diskid), 10, '0') AS id
FROM ".TBL_DATA.'
WHERE diskid NOT REGEXP "[^0-9]" AND
owner_id = '.get_current_user_id().'
ORDER BY id';
// sql looks strange but fixes problems with users who change their
// diskid_digits while they have already movies in their DB.
// added owner_id as fix for https://github.com/andig/videodb/issues/6
$results = runSQL($SQL);
// find first 'free' diskId
$lastid = 0;
foreach ($results as $result)
{
$thisid = preg_replace('/^0+/','',$result['id']);
if ($lastid + 1 < $thisid) break;
$lastid = $thisid;
}
// return the found id
return str_pad($lastid + 1, $digits, '0', STR_PAD_LEFT);
}
/**
* Strip leading articles
*
* @param string $field Input field to be stripped
* @return string Input with articles rearranged to end of string
*/
function removeArticles($field)
{
$articles = array('the ', 'la ', 'a ', 'der ', 'die ', 'das ', 'des ', 'dem ', 'den ',
'ein ', 'eine ', 'eines ', 'le ', 'el ', "l'", 'il ', 'les ', 'i ',
'o ', 'un ', 'los ', 'de ', 'an ', 'una ', 'las ', 'gli ', 'het ',
'lo ', 'os ', 'az ', 'ha-', 'een ', 'det ', 'oi ', 'ang ', 'ta ',
'al-', 'uno ', "un'", 'ett ', 'mga ', 'Ï ', 'Ç ', 'els ', 'Ôï ', 'Ïé ');
foreach ($articles as $article)
{
if (preg_match("/^$article+/i", $field))
{
$field = trim(preg_replace("/(^$article)(.+)/i", "$2, $1", $field));
break;
}
}
return $field;
}
/**
* Prepare item for display based on input data
*/
function echoInput($data)
{
global $imdb_set_fields;
// error no owner specified
$video = array();
// select all fields according to list, plus id
foreach ($imdb_set_fields as $name)
{
$video[0][$name] = $data[$name];
}
return $video;
}
/**
* Prepare update SQL
*
* @param array $data key/value pairs of data
* @returns string result SQL, suitable for INSERT/UPDATE
*/
function prepareSQL($data, $setonly = false)
{
global $config, $imdb_set_fields, $db_null_fields, $db_zero_fields;
// get global variables into local scope
extract($data);
// Fix for Bugreport [1122052] Automatic DiskID generation problem
if ($config['autoid'] && !empty($diskid) && ($diskid == $autoid))
{
// in case DiskID is already used in meanwhile
// -> update to new DiskId
$diskid = getDiskId();
}
// set default mediatype
if (empty($mediatype)) $mediatype = $config['mediadefault'];
// set owner
if (is_numeric($owner_id)) $SQL = 'owner_id = '.$owner_id;
// rating up to 10
$rating = min($rating, 10);
// update all fields according to list
foreach ($imdb_set_fields as $name)
{
if ($setonly && !isset($$name)) continue;
// sanitize input
$$name = removeEvilTags($$name);
if (!is_null($$name))
{
$$name = html_entity_decode($$name);
}
// make sure no formatting contained in basic data
if (in_array($name, array('title', 'subtitle')))
{
$$name = trim(strip_tags($$name));
// string leading articles?
if ($config['removearticles'])
{
$$name = removeArticles($$name);
}
}
$SET = "$name = '".escapeSQL($$name)."'";
// special null/zero handling
if (empty($$name))
{
if (in_array($name, $db_null_fields))
$SET = "$name = NULL";
elseif (in_array($name, $db_zero_fields))
$SET = "$name = 0";
}
if ($SQL) $SQL .= ', ';
$SQL .= $SET;
}
return $SQL;
}
/**
* @param string $SQL set fields
* @param int $id id of item to update, insert if empty
* @param boolean $touch true specifies to update created data of item
*/
function updateDB($SQL, $id, $touch=false)
{
if ($id)
{
// update existing record
if ($touch)
{
// if the disk was on the wishlist and is now available, make sure it appears under 'new'
$SQL .= ', created = NOW()';
}
$SQL = 'UPDATE '.TBL_DATA.' SET '.$SQL.' WHERE id = '.$id;
runSQL($SQL);
}
else
{
// insert new record
$SQL = 'INSERT INTO '.TBL_DATA.' SET '.$SQL.', created = NOW()';
$id = runSQL($SQL);
}
return $id;
}
/**
* Process HTTP file upload
*/
function processUpload($id, $file, $mime, $name)
{
if (!(isset($_FILES['coverupload']) && is_uploaded_file($_FILES['coverupload']['tmp_name'])))
return;
// determine file extension
if (preg_match('=image/jpe?g=i', $mime))
{
$ext = 'jpg';
}
elseif (preg_match('=image/(gif|png)=i', $mime, $m))
{
$ext = $m[1];
}
elseif (preg_match('=application/octet-stream=i', $mime))
{
if (preg_match("/\.(jpe?g|gif|png)$/i", $name, $m))
{
$ext = $m[1];
}
}
// move to cache and update db
if (!empty($ext))
{
$coverfile = 'cache/img/'.$id.'.'.$ext;
if (move_uploaded_file($file, $coverfile))
{
// fix permission issues
chmod($coverfile, 0644);
$sql = "UPDATE ".TBL_DATA." SET imgurl='$coverfile' WHERE id=$id";
runSQL($sql);
}
}
}
?>

282
videodb/core/encoding.php Normal file
View File

@@ -0,0 +1,282 @@
<?php
/**
* Encoding functions
*
* Contains HTML and Unicode conversion functions
*
* @package Core
* @author Andreas Goetz <cpuidle@gmx.de>
* @version $Id: encoding.php,v 1.6 2013/03/10 16:25:35 andig2 Exp $
*/
/**
* Check if string contains unicode characters
*/
function is_utf8($str)
{
// array handling
if (is_array($str)) {
foreach($str as $k => $v) {
$res = is_utf8($v);
if (!$res) return(false);
}
return(true);
}
// From http://w3.org/International/questions/qa-forms-utf-8.html
return preg_match('%^(?:
[\x09\x0A\x0D\x20-\x7E] # ASCII
| [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte
| \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs
| [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte
| \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates
| \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3
| [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15
| \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16
)*$%xs', $str);
}
/**
* @author "Sebasti<74>n Grignoli" <grignoli@framework2.com.ar>
* @package Encoding
* @version 1.1
* @link http://www.framework2.com.ar/dzone/forceUTF8-es/
* @example http://www.framework2.com.ar/dzone/forceUTF8-es/
*/
function fix_utf8($text)
{
$utf8ToWin1252 = array(
"\xe2\x82\xac" => "\x80",
"\xe2\x80\x9a" => "\x82",
"\xc6\x92" => "\x83",
"\xe2\x80\x9e" => "\x84",
"\xe2\x80\xa6" => "\x85",
"\xe2\x80\xa0" => "\x86",
"\xe2\x80\xa1" => "\x87",
"\xcb\x86" => "\x88",
"\xe2\x80\xb0" => "\x89",
"\xc5\xa0" => "\x8a",
"\xe2\x80\xb9" => "\x8b",
"\xc5\x92" => "\x8c",
"\xc5\xbd" => "\x8e",
"\xe2\x80\x98" => "\x91",
"\xe2\x80\x99" => "\x92",
"\xe2\x80\x9c" => "\x93",
"\xe2\x80\x9d" => "\x94",
"\xe2\x80\xa2" => "\x95",
"\xe2\x80\x93" => "\x96",
"\xe2\x80\x94" => "\x97",
"\xcb\x9c" => "\x98",
"\xe2\x84\xa2" => "\x99",
"\xc5\xa1" => "\x9a",
"\xe2\x80\xba" => "\x9b",
"\xc5\x93" => "\x9c",
"\xc5\xbe" => "\x9e",
"\xc5\xb8" => "\x9f"
);
if (is_array($text)) {
foreach($text as $k => $v) {
$text[$k] = fix_utf8($v);
}
return $text;
}
$last = "";
while ($last <> $text) {
$last = $text;
$text = utf8_encode(utf8_decode(str_replace(array_keys($utf8ToWin1252), array_values($utf8ToWin1252), $text)));
}
$text = utf8_encode(utf8_decode(str_replace(array_keys($utf8ToWin1252), array_values($utf8ToWin1252), $text)));
return $text;
}
/**
* Decode string is utf-8. Typically used for later URL encoding of the string
*/
function utf8_smart_decode($str)
{
return (is_utf8($str)) ? utf8_decode($str) : $str;
}
/**
* Like html_entity_decode() but also supports numeric entities.
* Output encoding is ISO-8852-1.
*
* @author www.php.net
* @param string $string html entity loaded string
* @return string html entity free string
*/
function html_entity_decode_all($string)
{
// replace numeric entities
$string = preg_replace_callback('~&#x([0-9a-f]+);~i', '_callback_chr_hexdec', $string);
$string = preg_replace_callback('~&#([0-9]+);~', '_callback_chr', $string);
# utf8 version commented out
# $string = preg_replace_callback('~&#x([0-9a-f]+);~i', '_callback_code2utf_hexdec', $string);
# $string = preg_replace_callback('~&#([0-9]+);~', '_callback_code2utf', $string);
// replace literal entities
$trans_tbl = get_html_translation_table(HTML_ENTITIES);
$trans_tbl = array_flip($trans_tbl);
# utf8 version commented out
# foreach (get_html_translation_table(HTML_ENTITIES) as $val=>$key) $trans_tbl[$key] = utf8_encode($val);
return strtr($string, $trans_tbl);
}
/**
* Like html_entity_decode() but also supports numeric entities.
* Output encoding is UTF-8.
*
* @author www.php.net
* @param string $string html entity loaded string
* @return string html entity free string
*/
function html_entity_decode_all_utf8($string)
{
// replace numeric entities
# non-utf8 version commented out
# $string = preg_replace_callback('~&#x([0-9a-f]+);~i', '_callback_chr_hexdec', $string);
# $string = preg_replace_callback('~&#([0-9]+);~', '_callback_chr', $string);
$string = preg_replace_callback('~&#x([0-9a-f]+);~i', '_callback_code2utf_hexdec', $string);
$string = preg_replace_callback('~&#([0-9]+);~', '_callback_code2utf', $string);
// replace literal entities
# non-utf8 version commented out
# $trans_tbl = get_html_translation_table(HTML_ENTITIES);
# $trans_tbl = array_flip($trans_tbl);
foreach (get_html_translation_table(HTML_ENTITIES) as $val=>$key) $trans_tbl[$key] = utf8_encode($val);
return strtr($string, $trans_tbl);
}
/**
* Returns the utf-8 encoding corresponding to the unicode character value
* @author from php.net, courtesy - romans@void.lv
*/
function code2utf($num)
{
if ($num < 128) return chr($num);
if ($num < 2048) return chr(($num >> 6) + 192) . chr(($num & 63) + 128);
if ($num < 65536) return chr(($num >> 12) + 224) . chr((($num >> 6) & 63) + 128) . chr(($num & 63) + 128);
if ($num < 2097152) return chr(($num >> 18) + 240) . chr((($num >> 12) & 63) + 128) . chr((($num >> 6) & 63) + 128) . chr(($num & 63) + 128);
return '';
}
/**
* Clean HTML entities and replace &nbsp; special spaces
*
* @author Andreas Goetz <cpuidle@gmx.de>
* @param string $string html entity loaded string
* @return string html entity free string
*/
function html_clean($str)
{
return trim(str_replace(chr(160), ' ', html_entity_decode_all($str)));
}
/**
* Clean HTML entities, tags and replace &nbsp; special spaces
* Output encoding is UTF-8.
*
* @author Andreas Goetz <cpuidle@gmx.de>
* @param string $str html entity loaded string
* @return string html entity free string
*/
function html_clean_utf8($str)
{
# this replacement breaks unicode enitity encoding as A0 might occor as part of any character
# $str = str_replace(chr(160), ' ', $str);
$str = html_entity_decode_all_utf8(strip_tags($str));
return trim($str);
}
/**
* Chance character set encoding for hierarchical array
*
* @param mixed $data string or hierarchical array to convert
* @return mixed data in target encoding
*/
function iconv_array($source_encoding, $target_encoding, $data)
{
if (is_array($data))
{
// recursive call for array conversion
foreach ($data as $key => $val)
{
$data[$key] = iconv_array($source_encoding, $target_encoding, $val);
}
}
else
{
// finally convert string value
$data_saved = $data; // save data for output on error page if signalled
$data = iconv($source_encoding, $target_encoding."//TRANSLIT", (string)$data);
if ($data === FALSE)
{
errorpage('Character set conversion error', "Error converting from $source_encoding to $target_encoding. <br> String <br> $data_saved");
}
}
return $data;
}
/**
* Convert HTML to plain text for some common entities
*/
function html_to_text($str)
{
// create list items
$str = preg_replace("#<li.*?>#i", "\n-", $str);
// de-html line breaks
$str = preg_replace('#<(br|p).*?>#i', "\n", $str);
// avoid double line breaks
$str = preg_replace("#\n+#", "\n", $str);
return $str;
}
/**
* Ensure that there is only one match from a preg_replace_callback and return it
*/
function _get_only_match_from_callback($matches) {
assert(sizeof($matches) === 2);
return $matches[1];
}
/**
* apply chr on the only match of a preg_replace_callback
*/
function _callback_chr($matches) {
return chr(_get_only_match_from_callback($matches));
}
/**
* apply hexdec and chr on the only match of a preg_replace_callback
*/
function _callback_chr_hexdec($matches) {
return chr(hexdec(_get_only_match_from_callback($matches)));
}
/**
* apply code2utf on the only match of a preg_replace_callback
*/
function _callback_code2utf($matches) {
return code2utf(_get_only_match_from_callback($matches));
}
/**
* apply hexdec and code2utf on the only match of a preg_replace_callback
*/
function _callback_code2utf_hexdec($matches) {
return code2utf(hexdec(_get_only_match_from_callback($matches)));
}
?>

View File

@@ -0,0 +1,81 @@
<?php
/**
* Export functions. Returns standardized data for export.
*
* @package videoDB
* @author Andreas Götz <cpuidle@gmx.de>
* @author Chinamann <chinamann@users.sourceforge.net>
* @version $Id: export.core.php,v 1.8 2013/03/15 16:42:46 andig2 Exp $
*/
require_once './core/genres.php';
function listExports($link, $omit = array('rss'))
{
global $config;
$exports = array('xls' => 'Microsoft Excel',
'pdf' => 'Adobe PDF',
'xml' => 'XML',
'rss' => 'RSS Feed');
$res = array();
foreach ($exports as $export => $title)
{
if ($config[$export] &! in_array($export, $omit))
$res[] = array('type' => $export, 'title' => $title, 'link' => $link);
}
return($res);
}
function exportData($WHERE)
{
$SQL = 'SELECT '.TBL_DATA.'.*,
'.TBL_USERS.'.name AS owner,
'.TBL_MEDIATYPES.'.name AS mediatype,
'.TBL_LENT.'.who AS lentto,
CASE WHEN '.TBL_USERSEEN.'.video_id IS NULL THEN 0 ELSE 1 END AS seen
FROM '.TBL_DATA.'
LEFT JOIN '.TBL_USERS.' ON '.TBL_DATA.'.owner_id = '.TBL_USERS.'.id
LEFT JOIN '.TBL_USERSEEN.' ON '.TBL_DATA.'.id = '.TBL_USERSEEN.'.video_id AND '.TBL_USERSEEN.'.user_id = '.get_current_user_id().'
LEFT JOIN '.TBL_LENT.' ON '.TBL_DATA.'.diskid = '.TBL_LENT.'.diskid
LEFT JOIN '.TBL_MEDIATYPES.' ON mediatype = '.TBL_MEDIATYPES.'.id '.
$WHERE;
$result = runSQL($SQL);
// do adultcheck
if (is_array($result))
{
$result = array_filter($result, function($video) {return adultcheck($video["id"]);});
}
// genres
for($i=0; $i<count($result); $i++)
{
$result[$i]['genres'] = getItemGenres($result[$i]['id'], true);
}
return $result;
}
/**
* Limit string length while honoring word breaks
*
* @param string string to trim
* @param int target length
* @result string trimmed string
*/
function leftString($plot, $text_length)
{
if (strlen($plot) > $text_length+3)
{
$plot = substr($plot, 0, $text_length);
$space = strrpos($plot, ' ');
if ($space) $plot = substr($plot, 0, $space);
$plot .= '...';
}
return $plot;
}
?>

View File

@@ -0,0 +1,279 @@
<?php
/**
* General functions
*
* Contains globally available tool functions. It is included in every
* page and sets up some defaults like error reporting, environment
* setups and config loading
*
* @package Core
* @author Andreas Goetz <cpuidle@gmx.de>
* @author Andreas Gohr <a.gohr@web.de>
* @author Chinamann <chinamann@users.sourceforge.net>
* @version $Id: functions.core.php,v 1.1 2013/04/26 15:08:30 andig2 Exp $
*/
if (!function_exists('errorpage')) {
function errorpage($title = 'An error occured', $body = '', $stacktrace = false) {
}
}
/**
* Output debug info
*
* @author Andreas Goetz <cpuidle@gmx.de>
* @param mixed $var Variable to dump
* @param bool $ret Return result instead of outputting
* @param bool $plain Indicate that \n separator is used
*/
function dump($var, $ret = false, $plain = false)
{
global $argv;
if (isset($argv) && is_array($argv) && count($argv) > 0) $plain = true;
if (is_array($var) || is_object($var))
$var = print_r($var, 1);
else if (is_bool($var))
$var = ($var) ? 'TRUE' : 'FALSE';
$var .= (is_array($argv)&&count($argv) > 0 || $plain) ? "\n" : "<br/>\n";
if ($ret) return $var;
echo $var;
}
/**
* Write variable to file
*
* @author Chinamann <chinamann@users.sourceforge.net>
* @param string $filename Filename to dump to
* @param var $var Variable to dump
*/
function file_append($filename, $var, $append = true)
{
$log = fopen($filename, $append ? 'a' : 'w');
fwrite($log, dump($var, true, true));
fclose($log);
}
/**
* Write to debug log
*
* @author Andreas Goetz <cpuidle@gmx.de>
* @param mixed $var Variable to dump
*/
function dlog($var)
{
file_append(LOG_FILE, $var);
}
/**
* safe formoutputter
*
* @param string $name The input string
* @return string The cleaned string
*/
function formvar($name)
{
if (!is_null($name))
{
return htmlspecialchars($name);
}
return "";
}
/**
* Get high resolution time
*
* @return integer current time in microseconds
*/
function getmicrotime()
{
list($usec, $sec) = explode(' ', microtime());
return ((float)$usec + (float)$sec);
}
/**
* Return mysqli db connection object
*
* @return mysqli database handle
*/
function getConnection()
{
global $config, $dbh;
$dbh = mysqli_connect('p:'.$config['db_server'], $config['db_user'], $config['db_password'], $config['db_database']);
if (mysqli_connect_error())
errorpage('DB Connection Error',
"<p>Edit the database settings in <code>".CONFIG_FILE."</code>.</p>
<p>Alternatively, consider running the <a href='install.php'>installation script</a>.</p>");
if (DB_CHARSET)
{
if (mysqli_set_charset($dbh, DB_CHARSET) === false)
errorpage('DB Link Error', 'Couldn\'t set encoding to '.DB_CHARSET);
}
return($dbh);
}
/**
* Escape SQL string according to current DB charset settings
*
* @param string $sql_string SQL string to escape
* @return string escaped string
*/
function escapeSQL($sql_string)
{
global $dbh;
if (!is_null($sql_string))
{
if (!is_resource($dbh)) $dbh = getConnection();
return(mysqli_real_escape_string($dbh, $sql_string));
}
return ("");
}
/**
* SQL wrapper for all Database accesses
*
* @param string $sql_string The SQL-Statement to execute
* @return mixed either the resultset as an array with hashes or the insertid
*/
function runSQL($sql_string, $verify = true)
{
global $config, $dbh, $SQLtrace;
if ($config['debug'])
{
dlog("\n".$_SERVER['REQUEST_URI']);
if (function_exists('xdebug_get_function_stack')) dlog(join(' -> ', array_column(xdebug_get_function_stack(), 'function')));
dlog($sql_string);
$timestamp = getmicrotime();
}
if (!is_resource($dbh)) $dbh = getConnection();
$res = mysqli_query($dbh, $sql_string);
// mysqli_db_query returns either positive result ressource or true/false for an insert/update statement
if ($res === false)
{
$result = false;
if ($verify)
{
// report DB Problem
errorpage('Database Problem', mysqli_error($dbh)."\n<br />\n".$sql_string, true);
}
}
elseif ($res === true)
{
// on insert, return id of created record
$result = mysqli_insert_id($dbh);
}
else
{
// return associative result array
$result = array();
for ($i=0; $i<mysqli_num_rows($res); $i++)
{
$result[] = mysqli_fetch_assoc($res);
}
mysqli_free_result($res);
}
if ($config['debug'])
{
$timestamp = getmicrotime() - $timestamp;
dlog('Time: '.$timestamp);
// collect all SQL info for debugging
$SQLtrace[] = array('sql' => $sql_string, 'time' => $timestamp);
}
# mysqli_close($dbh);
return $result;
}
/**
* Checks if the page is accessed from within the local net.
*
* @return bool true if localnet
*/
function localnet()
{
global $config;
return (preg_match('/'.$config['localnet'].'/', $_SERVER['REMOTE_ADDR']));
}
/**
* checks if the page is accessed from within the local net.
* If not, displays a simple error page and exits
*/
function localnet_or_die()
{
if (!localnet()) errorpage('Forbidden', 'You are not allowed to access this page');
}
/**
* Set connection encoding according to config file or language specification
*/
function db_set_encoding()
{
global $config, $lang;
// set connection character set and collation
if (DB_CHARSET)
{
$sql = "SET NAMES '".DB_CHARSET."'";
$collation = ($lang['collation']) ? DB_CHARSET.'_'.$lang['collation'] : DB_COLLATION;
if ($collation) $sql .= " COLLATE '".$collation."'";
runSQL($sql);
}
}
/**
* Redirect to new location
*
* @author Andreas Goetz <cpuidle@gmx.de>
* @param string $dest Redirect destination
* @todo Read somewhere that according to RFC redirects need to specify full URI
*/
function redirect($dest)
{
header('Location: '.$dest);
exit();
}
/**
* Convert an array of associative arrays (e.g. a database query result) to an associative key=>value array
*
* Sample: array_associate( 0=>(a=>1a, b=1b) 1=>(a=>2a, b=>2b), "a", "b" ) gives 1a=>1b, 2a=>2b
*
* If $value is false, the whole array is associated instead of a specific value
*
* Sample: array_associate( 0=>(a=>1a, b=1b) 1=>(a=>2a, b=>2b), "a", false ) gives 1a=>(b=>1b), 2a=>(b=>2b
*
* TODO Check if this can be replaced by PHP5.5 array_column() function
*
* @author Andreas Goetz <cpuidle@gmx.de>
* @param $ary SQL result array
* @param $key key index name
* @param $value value index name
* @return array resulting associative array
*/
function array_associate($ary, $columnKey, $value = false)
{
$res = array();
foreach ($ary as $row)
{
$res[$row[$columnKey]] = ($value) ? $row[$value] : $row;
}
return $res;
}
?>

1095
videodb/core/functions.php Normal file

File diff suppressed because it is too large Load Diff

137
videodb/core/genres.php Normal file
View File

@@ -0,0 +1,137 @@
<?php
/**
* Genre functions
*
* Contains functions for working with video genres
* moved from functions.php to genres.php
*
* @package Core
* @author Andreas Gohr <a.gohr@web.de>
* @author Andreas Götz <cpuidle@gmx.de>
* @version $Id: genres.php,v 1.14 2008/01/29 10:59:52 veal Exp $
*/
/**
* Map movie genres to versions existing in db
*
* @author Andreas Goetz <cpuidle@gmx.de>
* @param array $genres A list of input genres
* @return array The mapped genres result array
*/
function mapGenres($genres)
{
global $dbgenres;
// load genres from DB once
if (empty($dbgenres))
{
$dbgenres = array();
foreach (runSQL('SELECT id, name FROM '.TBL_GENRES.' ORDER BY name') as $row)
{
$dbgenres[] = $row['name'];
}
}
foreach ($genres as $in_genre)
{
$mapped_genre = '';
$mapped_percent = 0;
$in_genre = trim($in_genre);
// direct match?
if (in_array($in_genre, $dbgenres))
{
$gens[] = $in_genre;
}
else
{
// possible approximate match
foreach ($dbgenres as $genre_name)
{
// calculate similiarity and find best match
$chars = similar_text($in_genre, $genre_name, $percent);
if ($percent >= 50)
{
if (stristr($in_genre, $genre_name)) $percent += 10;
if ($percent > $mapped_percent)
{
$mapped_genre = $genre_name;
$mapped_percent = $percent;
}
}
}
if ($mapped_genre) $gens[] = $mapped_genre;
}
}
return array_unique($gens);
}
/**
* returns the genreID for a given name from the 'genres' table
*
* @todo check if this can be moved to edit.php
* @param string $name the name of the genre
* @return integer $genre the genre id
*/
function getGenreId($name)
{
$name = escapeSQL($name);
$result = runSQL("SELECT id FROM ".TBL_GENRES." WHERE LCASE(name) = LCASE('".$name."')");
return $result[0]['id'];
}
/**
* retrieve genre ids/ genres of a video
*
* @param integer $id ID of the video
* @param boolean $names include genre names in output
* @return array genre id's OR
* @return array associative array of genre ids and names
*/
function getItemGenres($id, $names = false)
{
$genres = array();
if (empty($id)) return $genres;
$SELECT = 'SELECT genres.id, genres.name
FROM '.TBL_GENRES.' AS genres, '.TBL_VIDEOGENRE.' AS videogenre
WHERE genres.id = videogenre.genre_id
AND videogenre.video_id = '.$id;
$result = runSQL($SELECT);
if ($names) return $result;
foreach ($result as $row)
{
$genres[] = $row['id'];
}
return $genres;
}
/**
* save genres for a movie
*
* @todo check if this can be moved to edit.php
* @param integer $id ID of the video
* @param array $genres genre IDs
*/
function setItemGenres($id, $genres)
{
// Delete all genres for id
runSQL('DELETE FROM '.TBL_VIDEOGENRE.' WHERE video_id = '.$id);
if (count($genres))
{
$genres = array_unique($genres);
foreach($genres as $genre)
{
runSQL('INSERT INTO '.TBL_VIDEOGENRE.' SET video_id = '.$id.', genre_id = '.$genre);
}
}
}
?>

111
videodb/core/httpcache.php Normal file
View File

@@ -0,0 +1,111 @@
<?php
/**
* HTTP caching functions
*
* Enable use of HTTP 304 headers for unmodified content to save bandwidth
*
* @package Core
* @author Andreas Götz <cpuidle@gmx.de>
* @version $Id: httpcache.php,v 1.5 2010/11/05 10:38:47 andig2 Exp $
*/
/**
* Start output buffering
*/
function httpCacheCaptureStart()
{
ob_start();
}
/**
* Stop output buffering
*
* @param string MD5 hash of content
*/
function httpCacheCaptureEnd()
{
$content = ob_get_contents();
ob_end_clean();
return $content;
}
/**
* Get last modified data for given etag
* Checks session for known etag and timestamp
*/
function httpCacheCheckTag($template, $etag)
{
if ($etag != $_SESSION['vdb'][$template]['etag'])
{
$lastmod = time();
$_SESSION['vdb'][$template]['etag'] = $etag;
$_SESSION['vdb'][$template]['time'] = $lastmod;
}
else
{
$lastmod = $_SESSION['vdb'][$template]['time'];
}
return($lastmod);
}
/**
* Output 304 Not Modified header
* Require browser to re-check on next request
*/
function httpCacheHeaders($etag, $expires)
{
header(php_sapi_name() == 'cgi' ? 'Status: 304 Not Modified' : 'HTTP/1.x 304 Not Modified');
header("ETag: {$etag}");
header("Cache-Control: private, max-age={$expires}, pre-check=0, post-check=0");
header("Content-Length: 0");
header("Content-Type: !invalid");
exit();
}
/**
* Check if output was modified since last request
* If unmodifed, output 304 Not Modified header
* Otherwise add additional ETag and LastModified headers
*/
function httpCacheOutput($template, $content)
{
$etag = '"'.md5($content).'"';
// check if 'sending' is necessary (using cache functions)
$sendbody = true;
$expires = 0;
$lastmod = httpCacheCheckTag($template, $etag);
// check 'If-Modified-Since' header
if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && gmdate('D, d M Y H:i:s', $lastmod)." GMT" == trim($_SERVER['HTTP_IF_MODIFIED_SINCE']))
{
httpCacheHeaders($etag, $expires);
}
// check 'If-None-Match' header (ETag)
if ($sendbody && isset($_SERVER['HTTP_IF_NONE_MATCH']))
{
$inm = explode(',', $_SERVER['HTTP_IF_NONE_MATCH']);
foreach ($inm as $i)
{
if (trim($i) != $etag) continue;
httpCacheHeaders($etag, $expires);
}
}
// send with caching headers (enable cache for one day)
$exp_gmt = gmdate('D, d M Y H:i:s', time() + $expires).' GMT';
$mod_gmt = gmdate('D, d M Y H:i:s', $lastmod).' GMT';
header("Expires: {$exp_gmt}");
header("Last-Modified: {$mod_gmt}");
header("Cache-Control: private, max-age={$expires}, pre-check=0, post-check=0");
header("Pragma: !invalid");
header("ETag: {$etag}");
echo $content;
}
?>

246
videodb/core/httpclient.php Normal file
View File

@@ -0,0 +1,246 @@
<?php
/**
* HTTP client functions
*
* @todo Encapsulate httpClient and Cache as separate classes
*
* @package Core
* @author Andreas Goetz <cpuidle@gmx.de>
* @author Andreas Gohr <a.gohr@web.de>
* @author Chinamann <chinamann@users.sourceforge.net>
* @version $Id: httpclient.php,v 1.21 2013/04/26 15:09:35 andig2 Exp $
*/
require_once 'core/cache.php';
require_once 'vendor/autoload.php';
use GuzzleHttp\Psr7 as Psr7;
/**
* Reads a saved HTTP response from a cachefile.
* If caching is globally disabled ($config['IMDBage'] <= 0), file is not loaded.
*
* @param string $url URL of the cached response
* @return mixed HTTP Response, false on errors
*/
function getHTTPcache($url)
{
global $config;
if (@$config['cache_pruning'])
{
$cache_file = cache_get_filename($url, CACHE_HTML);
cache_prune_folder(dirname($cache_file).'/', $config['IMDBage']);
}
return cache_get($url, CACHE_HTML, $config['IMDBage'], true);
}
/**
* Saves a HTTP resonse to a cachefile
* If caching is globally disabled ($config['IMDBage'] <= 0), file is not saved.
*
* @param string $url URL of the response
* @param mixed $resp HTTP Response
*/
function putHTTPcache($url, $data)
{
global $config;
// for debugging purposes track there the request originated
$data['source'] = $url;
cache_put($url, $data, CACHE_HTML, $config['IMDBage'], true);
}
/**
* Extract source encoding from HTML code or HTTP header otherwise
*/
function get_response_encoding($response)
{
$header = $encoding = null;
// response array from cache
if (is_array($response)) {
if (isset($response['header']['Content-Type'])) {
$header = $response['header']['Content-Type'];
}
}
else {
// Psr response
$header = $response->getHeader('Content-Type');
}
if ($header) {
$parsed = Psr7\parse_header($header);
if (array_key_exists('charset', $parsed[0]))
{
$encoding = strtolower($parsed[0]['charset']);
}
}
if (!$encoding)
{
$encoding = 'iso-8859-1';
}
return $encoding;
}
/**
* HTTP Client
*
* Returns the raw data from the given URL, uses proxy when configured
* and follows redirects
*
* @author Andreas Goetz <cpuidle@gmx.de>
* @param string $url URL to fetch
* @param bool $cache use caching? defaults to false
* @param string $post POST data, if nonempty POST is used instead of GET
* @param integer $timeout Timeout in seconds defaults to 15
* @return mixed HTTP response
*/
function httpClient($url, $cache = false, $para = null, $reload = false)
{
static $referer = 'https://www.imdb.com/search/';
global $config;
$client = new GuzzleHttp\Client();
$requestConfig = [];
$headers = ''; // additional HTTP headers, used for post data
if (!empty($para) && array_key_exists('cookies', $para) && $para['cookies'])
{
$jar = new GuzzleHttp\Cookie\CookieJar();
$requestConfig += ['cookies' => $jar];
}
$method = 'GET';
$post = isset($para['post']) ? $para['post'] : '';
if ($post)
{
$method = 'POST';
$requestConfig += ['headers' => ['Content-Type' => 'application/x-www-form-urlencoded']];
$requestConfig += ['body' => $post];
}
// get data from cache?
if ($cache &! $reload)
{
$resp = getHTTPcache($url.$post);
if ($resp !== false)
{
$resp['cached'] = true;
return $resp;
}
}
// proxy setup
if (!empty($config['proxy_host']) && !$para['no_proxy'])
{
$server = $config['proxy_host'];
if (!($port = @$config['proxy_port']))
{
$port = 8080;
}
$requestConfig += ['proxy' => sprintf('tcp://%s:%d', $server, $port)];
}
// additional request headers
if (!empty($para) && array_key_exists('header', $para) && $para['header'])
{
$requestConfig += ['headers' => $para['header']];
}
if (empty($requestConfig['headers']['Accept'])) $requestConfig['headers']['Accept'] = 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8';
if (empty($requestConfig['headers']['Accept-Language'])) $requestConfig['headers']['Accept-Language'] = ((isset($config['acclangbrowser']) && $config['acclangbrowser']) ? filter_input(INPUT_SERVER, 'HTTP_ACCEPT_LANGUAGE') : 'en-US;q=0.7,en;q=0.3');
if (empty($requestConfig['headers']['DNT'])) $requestConfig['headers']['DNT'] = '1';
if (empty($requestConfig['headers']['User-Agent'])) $requestConfig['headers']['User-Agent'] = filter_input(INPUT_SERVER, 'HTTP_USER_AGENT');
if (empty($requestConfig['headers']['Referer'])) $requestConfig['headers']['Referer'] = $referer;
$resp = $client->request($method, $url, $requestConfig);
$response['error'] = '';
$response['url'] = $url;
$response['success'] = false;
$response['encoding'] = get_response_encoding($resp);
$response['header'] = $resp->getHeaders();
$response['data'] = (string) $resp->getBody();
if ($config['debug']) echoHeaders($response['header'])."<p>";
if ($config['debug']) echo "data:<br>".htmlspecialchars($response['data'])."<p>";
// log response
if ($config['httpclientlog'])
{
$log = fopen('httpClient.log', 'a');
fwrite($log, headers_to_string($response['header']));
fclose($log);
}
// verify status code
if ($resp->getStatusCode() != 200)
{
$response['error'] = 'Server returned wrong status: ' . $resp->getStatusCode();
$response['error'] .= " Reason: " . $resp->getReasonPhrase();
return $response;
}
$response['success'] = true;
// @todo i'm not sure on the side-effects of setting the previous requested URL as referer
// for the next, so disabled for now. might be something to investigate...
//$referer = $url;
// commit successful request to cache
if ($cache)
{
putHTTPcache($url.$post, $response);
}
return $response;
}
/**
* Print all header info using echo
* @param response Object homepage Psr7\Response
*/
function echoHeaders($headers)
{
foreach ($headers as $name => $values) {
echo $name . ': ' . implode(', ', $values) . "<br>";
}
}
function headers_to_string($headers)
{
$result = '';
foreach ($headers as $name => $values) {
$result .= $name . ': ' . implode(', ', $values) . "\n";
}
return $result;
}
/**
* Downloads an URL to the given local file
*
* @param string $url URL to download
* @param string $local Full path to save to
* @return bool true on succes else false
*/
function download($url, $local)
{
$resp = httpClient($url);
if (!$resp['success'])
{
return false;
}
return(@file_put_contents($local, $resp['data']) !== false);
}
?>

68
videodb/core/ids.php Normal file
View File

@@ -0,0 +1,68 @@
<?php
/**
* IDS setup
*
* @package Core
* @author Andreas Goetz <cpuidle@gmx.de>
* @version $Id: ids.php,v 1.2 2010/02/01 22:38:42 andig2 Exp $
*/
// set the include path properly for PHPIDS
set_include_path(
get_include_path()
. PATH_SEPARATOR
. './lib/'
);
if (!session_id()) {
session_start();
}
require_once 'IDS/Init.php';
try {
$init = IDS_Init::init(dirname(__FILE__) . '/../lib/IDS/Config/Config.ini');
$init->config['General']['base_path'] = dirname(__FILE__) . '/../lib/IDS/';
$init->config['General']['use_base_path'] = true;
$init->config['Caching']['caching'] = 'file';
$request = array(
'GET' => $_GET,
'POST' => $_POST,
'COOKIE' => $_COOKIE
);
$ids = new IDS_Monitor($request, $init);
$result = $ids->run();
if (!$result->isEmpty() && $result->getImpact() > 50)
{
require_once 'IDS/Log/Database.php';
require_once 'IDS/Log/Composite.php';
$compositeLog = new IDS_Log_Composite();
$compositeLog->addLogger(
IDS_Log_Database::getInstance($init)
);
$compositeLog->execute($result);
$hta = @file_get_contents('.htaccess');
if (preg_match('/(.+?)^(allow from all.*)/ms', $hta, $m))
{
$addr = $_SERVER['REMOTE_ADDR'];
// block whole subnet
$addr = implode('.', array_slice(explode('.', $addr), 0, 3));
$hta = $m[1] . 'deny from '.$addr."\n" . $m[2];
@file_put_contents('.htaccess', $hta);
}
header("HTTP/1.0 403 Forbidden");
die('Your IP has been blocked.<br/>To find out why visit <a href="http://sourceforge.net/mailarchive/forum.php?forum_name=videodb-devel">http://sourceforge.net/mailarchive/forum.php?forum_name=videodb-devel</a>');
}
} catch (Exception $e) {
//this shouldn't happen and if it does you don't want the notification public.
}
?>

View File

@@ -0,0 +1,326 @@
<?php
/**
* Installer functions
*
* Create database, tables and config file
*
* @package Setup
* @author Andreas Goetz <cpuidle@gmx.de>
* @version $Id: install.core.php,v 1.11 2010/02/18 15:15:37 andig2 Exp $
*/
/**
* Build formatted message string for html output
*
* @param string $msg Message to print
* @param string $color Color code for <div> tag
* @param boolean $print If true, output directly, else append to message string
*/
function showmessage($msg, $color, $print = false)
{
global $message;
if ($msg) $msg = "<span style='color: $color'>$msg</span><br/><br/>\n";
if ($print)
{
// print directly
echo $msg;
}
else
{
// return
$message .= $msg;
}
}
/**
* Prepare formatted error message for output
*
* @param string $msg Message to print
* @param boolean $print If true, output directly, else append to message string
*/
function error($msg, $print = false)
{
showmessage($msg, 'red', $print);
}
/**
* Prepare formatted warning message for output
*
* @param string $msg Message to print
* @param boolean $print If true, output directly, else append to message string
*/
function warn($msg, $print = false)
{
showmessage($msg, 'orange', $print);
}
/**
* Prepare formatted info message for output
*
* @param string $msg Message to print
* @param boolean $print If true, output directly, else append to message string
*/
function info($msg, $print = false)
{
showmessage($msg, 'green', $print);
}
/**
* Recursively delete files from directory
* used for Smarty cache cleanup during installation
*
* @param string $dir Directory name
* @param boolean $recursive Recurse into subfolders
*/
function delete_files($dir, $recursive = false)
{
if ($dh = @opendir($dir))
{
while (($file = readdir($dh)) !== false)
{
// next if . or ..
if (preg_match("/^\.\.?$/", $file)) continue;
// recursion?
if (is_dir("$dir/$file"))
{
if ($recursive) delete_files("$dir/$file", $recursive);
}
else
{
// delete file
unlink("$dir/$file");
}
}
closedir($dh);
if ($recursive) rmdir($dir);
}
}
/**
* Parse config file and replace settings according
* to associate array parameter
*
* @param array new parameter values
*/
function parse_config($vars)
{
$raw = null;
if ($file = @file_get_contents(CONFIG_FILE)) {
$raw = explode("\n", $file);
for ($i = 0; $i < count($raw); $i++)
{
foreach ($vars as $name => $val)
{
if (preg_match("/^(.*?'$name'.*?=\s*)(.*?)(\s*;.*?)$/", $raw[$i], $matches))
{
# quoted?
if (preg_match("/^[\"'].*[\"']$/", $matches[2])) $val = "'$val'";
$matches[2] = $val;
$raw[$i] = join('', array_slice($matches,1));
}
}
}
}
// fallback if config file is empty or invalid
if (count($raw) < 4)
{
$raw = array('<?php');
foreach ($vars as $name => $val)
{
$line = "\$config['$name'] = ";
$line .= (is_numeric($val)) ? "$val;" : "'$val';";
$raw[] = $line;
}
$raw[] = '?>';
}
return join("\n", $raw);
}
/**
* Parse database upgrade SQL file and
* build associate array of upgrade sql steps per version
*
* @return array associative array of upgrade steps
*/
function parse_upgrades($upgrade_file)
{
$cfg = file_get_contents($upgrade_file);
$raw = preg_split('/# changes in DB version /i', $cfg);
// loop through list of db upgrades split by comments
foreach ($raw as $str)
{
// upgrade version comment found?
if (preg_match('/(\d+)\s*#\s*(.+)/s', $str, $m))
{
$key = $m[1];
$str = $m[2];
}
else
{
if (empty($upgrades['3']))
{
// this is the first supported version
$key = 3;
}
else
{
// unexpected first db upgrade version found
trigger_error('Could not parse <a href="'.$upgrade_file.'">'.$upgrade_file.'</a>, please fix!', E_USER_ERROR);
}
}
$upgrades["$key"] = $str;
}
return $upgrades;
}
/**
* Callback function for adding prefix to table name in FROM clauses- extended to include sub queries
*
* $match[2] is table
*/
function sql_add_prefix($match)
{
global $db_prefix;
$match[2] = preg_replace('/(\'?\w+\'?)(\s*\w*)(,?)/', "`$db_prefix$1`$2$3", $match[2]);
return join(array_slice($match, 1, 3));
}
/**
* Prefix table names with table name prefix
* This will only work for simple queries with known structure (createtables.sql, updatedb.sql)
*
* @param string SQL command
* @return string SQL command with new table names
*/
function prefix_query($query)
{
global $db_prefix;
$query = preg_replace('/((CREATE|ALTER)\s+TABLE\s+(IF\s+NOT\s+EXISTS\s+)?)`?(\w+)`?/', "$1`$db_prefix$4`", $query);
$query = preg_replace('/((INSERT(\s+IGNORE)?|REPLACE)\s+INTO\s+)`?(\w+)`?/', "$1`$db_prefix$4`", $query);
$query = preg_replace('/(DROP\s+TABLE\s+(IF\s+EXISTS\s+)?)`?(\w+)`?(;?)/', "$1`$db_prefix$3`$4", $query);
// changed to allow only replace if sql update to row
$query = preg_replace('/(UPDATE\s+)`?(\w+)`?(\s+SET\s+)`?/', "$1`$db_prefix$2`$3", $query);
// FROM matches at beginning of string or subquery opened by left bracket
$query = preg_replace_callback( "/(\s+FROM\s+)(.*?)((\s+WHERE|ORDER|LEFT|RIGHT|OUTER|JOIN)|\)|$)/msi", 'sql_add_prefix', $query);
return $query;
}
/**
* Run multiple comma-separated queries
*
* @todo Split SQL queries more cleverly (currently not needed)
*
* @param string SQL commands
* @param ressource database handle
* @return mixed result array or false
*/
function runSQL($sql, $dbh, $verify = false)
{
$result = true;
foreach (explode(';', $sql) as $query)
{
$query = trim($query);
if (empty($query)) continue;
$query = prefix_query($query);
$result = mysqli_query($dbh, $query);
// error running SQL?
if ($result === false)
{
$sql = $query;
break;
}
}
// error running SQL?
if ($result === false)
{
if ($verify)
{
error("Error in SQL statement:<br/>".
"<code>$sql</code><br/>".mysqli_error($dbh));
}
}
// result set returned?
elseif ($result !== true)
{
$res = array();
for ($i=0; $i < mysqli_num_rows($result); $i++)
{
$res[] = mysqli_fetch_assoc($result);
}
mysqli_free_result($result);
return $res;
}
return $result;
}
/**
* Run all upgrade scripts passed as array step by step
*
* @param array $upgrade_steps Associative array of upgrade sql steps
*/
function db_upgrade($upgrade_steps)
{
global $dbh, $version;
global $step;
foreach ($upgrade_steps as $ver => $sql)
{
#info("Upgrading to database version: $ver");
$sql = preg_replace('/#.*\n/m','',$sql);
if (runSQL($sql, $dbh) === false)
{
error('Error upgrading database, try full install instead of upgrade:<br/>'.mysqli_error($dbh).
'<br/><br/><pre>'.$sql.'</pre>');
return false;
}
// perform additional upgrade steps
$upgrade_file = "./install/upgrade_v$ver.php";
if (file_exists($upgrade_file))
{
$result = include_once($upgrade_file);
if (!$result) return($false);
}
// add DB version information- this will make the separate update statement in upgrade.sql obsolete
runSQL("REPLACE INTO config (opt,value) VALUES ('dbversion', ".$ver.");", $dbh);
# runSQL("update config set value=25 where opt='dbversion'");
$version = $ver;
}
// perform generic upgrade validation
$upgrade_file = "./install/upgrade.php";
if (file_exists($upgrade_file))
{
$result = include_once($upgrade_file);
if (!$result) return($false);
}
return $version;
}
?>

278
videodb/core/output.php Normal file
View File

@@ -0,0 +1,278 @@
<?php
/**
* Output functions
*
* Functions for HTML output generation (Not templates!)
*
* @todo Check if this can be moved to smarty plugins
*
* @package Core
* @author Andreas Gohr <a.gohr@web.de>
* @author Andreas Goetz <cpuidle@gmx.de>
* @version $Id: output.php,v 1.29 2013/04/19 07:55:58 andig2 Exp $
*/
require_once './core/functions.php';
/**
* Return list of valid genres from db
*/
function getGenres()
{
$SELECT = 'SELECT id, name
FROM '.TBL_GENRES.'
ORDER BY name';
$result = runSQL($SELECT);
return $result;
}
/**
* Display genre checkboxes
*
* @param array $selected selected genre IDs
* @return string HTML for genre checkboxes
*/
function out_genres($selected)
{
global $config;
$result = getGenres();
$out = '<table class="genreselect"><tr>';
// get list of adult genres
$adultgenres = array();
if ($config['multiuser'] && !check_permission(PERM_ADULT))
{
$adultgenres = get_adult_genres();
}
$row = 0;
foreach ($result as $res)
{
// don't show adult genres if no permissions
if (in_array($res['id'], $adultgenres)) continue;
$out .= '<td nowrap="nowrap">';
$out .= '<input type="checkbox" name="genres[]" id="genreid'.$res['id'].'" value="'.$res['id'].'"';
if (@in_array ($res['id'], $selected))
{
$out .= ' checked="checked"';
}
$out .= '/>';
$out .= '<label for="genreid'.$res['id'].'">'.$res['name'].'</label>';
$out .= '</td>';
if ((++$row % 5) == 0)
{
$out .= '</tr><tr>';
}
}
$out .= '</tr></table>';
return $out;
}
/**
* Generate genres array for use with genre checkboxes
*
* @param array $selected selected genre IDs
* @return string HTML for genre checkboxes
*/
function out_genres2($item_genres = null)
{
global $config;
// get detailed genres
$all_genres = getGenres();
$adultgenres = array();
if ($config['multiuser'] && !check_permission(PERM_ADULT)) {
$adultgenres = get_adult_genres();
}
$genres = array();
foreach ($all_genres as $gen) {
// don't show adult genres if no permissions
if (in_array($gen['id'], $adultgenres)) continue;
// selected?
if ($item_genres) $gen['checked'] = (@in_array($gen['id'], $item_genres)) ? 1 : 0;
$genres[] = $gen;
}
return($genres);
}
/**
* Display selectbox with available Mediatypes
*
* @todo is this still used? can it be replaced by template code?
* @author <rob@robvonk.com>
* @return string HTML of selectbox
*/
function out_mediatypes($prefix = null)
{
global $config;
// select mediatypes
$SELECT = 'SELECT id, name
FROM '.TBL_MEDIATYPES.'
ORDER BY name';
$result = runSQL($SELECT);
// build associative array
# array('0' => '') +
$mediatypes = is_array($prefix) ? $prefix : array();
$mediatypes = $mediatypes + array_associate($result, 'id', 'name');
return $mediatypes;
}
/**
* All available language flags for config screen
*
* @param array $flags selected flags
* @return string HTML of Languageflags
*/
function out_languageflags($flags)
{
global $config;
$out = '';
$count = 1;
if (($dh = @opendir('./'.$config['templatedir'].'images/flags')) || ($dh = opendir('./images/flags')))
{
while (($file = readdir($dh)) !== false)
{
if (preg_match("/(.*)\.gif$/", $file, $matches))
{
$CHECK= (in_array($matches[1], $flags)) ? 'checked="checked"' : '';
$out .= '<input type="checkbox" name="languages[]" '.$CHECK.' id="flag_'.$matches[1].'" value="'.$matches[1].'" />';
$out .= '<label for="flag_'.$matches[1].'">';
$out .= '<img src="'.img('flags/'.$matches[1].'.gif').'" width="30" height="15" alt="'.ucwords($matches[1]).'" title="'.ucwords($matches[1]).'" />';
$out .= '</label> ';
if ($count++%4 == 0) $out.='<br />';
}
}
closedir($dh);
}
return $out;
}
/**
* List of owners names/ids with valid permissions for use in edit/index/search templates
*
* @author <cpuidle@gmx.de>
* @author Chinamann <chinamann@users.sourceforge.net>
* @param string $prefix Predefined additional Array entries
* @param string $permission Honor permissions for selectbox
* @return array Array with keys=ownernames and values=ownerids
*/
function out_owners($prefix = null, $permission = false, $keyIsId = false)
{
global $config;
// all permissions available if admin
if (check_permission(PERM_ADMIN)) $permission = false;
// hide guest if he/she can't login
$WHERES = ($config['denyguest']) ? " AND B.id != ".$config['guestid'] : '';
// select user ids- if permissions are required and no all access given, this is done against xrefs
if ($permission && !check_permission($permission))
{
// xref permissions
// TODO use cached permission table instead
$SELECT = 'SELECT DISTINCT(B.name) AS name, B.id
FROM '.TBL_PERMISSIONS.' A, '.TBL_USERS.' B
WHERE A.to_uid = B.id
AND A.from_uid = '.get_current_user_id().'
AND (A.permissions & '.$permission.') = '.$permission.$WHERES.'
ORDER BY name';
}
else
{
// all users +/- guest
$SELECT = 'SELECT B.id, B.name
FROM '.TBL_USERS.' B
WHERE 1=1 '.$WHERES.'
ORDER BY B.name';
}
$result = runSQL($SELECT);
$key = ($keyIsId) ? 'id' : 'name';
// build associative array
$owners = is_array($prefix) ? $prefix : array();
$owners = $owners + array_unique(array_associate($result, $key, 'name'));
return $owners;
}
/**
* MySQL-compatible list of owner ids with required access permission
*
* @author Andreas Goetz <cpuidle@gmx.de>
*/
function get_owner_ids($permission)
{
foreach($_SESSION['vdb']['permissions']['to_uid'] as $to_uid => $perm)
{
if ($permission & $perm) $ids[] = $to_uid;
}
return (count($ids)) ? join(',', $ids) : -1;
}
/**
* Present a size (in bytes) as a human-readable value
*
* @author http://php.net
*
* @param int $size size (in bytes)
* @param int $precision number of digits after the decimal point
* @return string
*/
function sizetostring($size, $precision = 0)
{
$sizes = array('YB', 'ZB', 'EB', 'PB', 'TB', 'GB', 'MB', 'kB', 'B');
$total = count($sizes);
while($total-- && $size > 1024) $size /= 1024;
return round($size, $precision).$sizes[$total];
}
// @todo unused
function img_avg_color($filename, $format=0)
{
// networked file
if (preg_match('/^http/i', $imgurl)) return(FALSE);
// not a valid image
if (!list($width, $height) = @getimagesize($filename)) return(FALSE);
// resample
switch (exif_imagetype($filename)) {
case 2:
$img = imagecreatefromjpeg($filename);
break;
case 3:
$img = imagecreatefrompng($filename);
break;
case 1:
$img = imagecreatefromgif($filename);
break;
}
$tmp = imagecreatetruecolor(1, 1);
if (!imagecopyresampled($tmp, $img, 0, 0, 0, 0, 1, 1, $width, $height)) return(FALSE);
$rgb = imagecolorat($tmp, 0, 0);
$r = dechex($rgb >> 16);
$g = dechex($rgb >> 8 & 0xFF);
$b = dechex($rgb & 0xFF);
return('#'.$r.$g.$b);
}
?>

457
videodb/core/pdf.php Normal file
View File

@@ -0,0 +1,457 @@
<?php
/**
* PDF Export functions
*
* Allows exporting movies to PDF
* Requires FPDF libaray (http://www.fpdf.org)
*
* @package Core
* @link http://www.fpdf.org
* @author Andreas Götz <cpuidle@gmx.de>
* @version $Id: pdf.php,v 1.36 2013/03/15 16:42:46 andig2 Exp $
*/
require_once './core/functions.php';
require_once './core/cache.php';
require_once './core/export.core.php';
require_once './engines/engines.php';
require_once './core/VariableStream.class.php';
define('FPDF', './vendor/setasign/fpdf');
define('FPDF_FONTPATH', FPDF.'/font/');
require_once FPDF.'/fpdf.php';
require_once './lib/fpdf2file/fpdf2file.php';
/**
* Copied from FPDF tutorial 3
* enhanced with memory image creation for gif->png conversion
*
* @link http://www.fpdf.org/?go=script&id=45
*/
class PDF extends FPDF2File
{
var $B;
var $I;
var $U;
var $HREF;
var $GDCount = 0;
var $Scale = 0; // dont rescale images
function FPDF2File($orientation='P', $unit='mm', $format='A4')
{
//Call parent constructor
$this->FPDF($orientation,$unit,$format);
//Initialization
$this->B=0;
$this->I=0;
$this->U=0;
$this->HREF='';
}
function GDImage($file, $x, $y, $im, $w=0, $h=0, $link='', $type='png')
{
// ouput the GD image $im
ob_start();
$func = 'image'.$type; // image creation function according to type
$func($im);
$data = ob_get_contents();
ob_end_clean();
// create file-unique variable name to not duplicate images for pdf
$file = (empty($file)) ? $this->GDCount++ : preg_replace('/[\s\/\.]/', '_', $file);
$name = 'pdf_image_'.$file;
$GLOBALS[$name] = $data;
// call Image using in-memory PNG file
parent::Image('var://'.$name, $x, $y, $w, $h, $type, $link);
}
function Image($file, $x=null, $y=null, $w=0, $h=0, $ext='', $link='')
{
global $config;
$image_types = array(1 => 'gif', 2 => 'jpg', 3 => 'png', 6 => 'bmp');
list($width, $height, $ext, $attr) = getimagesize($file);
$ext = $image_types[$ext];
// find image loading function
switch($ext)
{
case 'jpg': $func = 'jpeg'; break;
case 'bmp': $func = 'wbmp'; break;
default: $func = $ext;
}
$func = 'imagecreatefrom'.$func;
// check if loading functions exists (especially for gif support)
$im = (function_exists($func)) ? $func($file) : imagecreatetruecolor(1,1);
// scaling requested?
if ($this->Scale)
{
$this->max_width = round($this->Scale * $config['pdf_image_max_width']);
$this->max_height = round($this->Scale * $config['pdf_image_max_height']);
$scale = min($this->max_width/$width, $this->max_height/$height);
$thumb_x = round($width * $scale);
$thumb_y = round($height * $scale);
}
// scaling requied?
if (($this->Scale) && (($thumb_x != $width) || ($thumb_y != $height)))
{
// create white truecolor image (in case original is transparent)
$target = imagecreatetruecolor($thumb_x, $thumb_y);
$white = imagecolorallocate($target, 255, 255, 255);
imagefilledrectangle($target, 0, 0, $thumb_x, $thumb_y, $white);
imagecopyresampled($target, $im, 0,0, 0,0, $thumb_x,$thumb_y, $width,$height);
$this->GDImage($file, $x, $y, $target, $w, $h, $link, 'jpeg'); // change to png if you receive acrobat errors
imagedestroy($target);
}
elseif ($ext == 'gif') {
// pdf doesn't support interlaced images
if (imageinterlace($im))
{
// claim non-interlaced image
imageinterlace($im, false);
}
$this->GDImage($file, $x, $y, $im, $w, $h, $link);
}
else {
parent::Image($file, $x, $y, $w, $h, $ext, $link);
}
imagedestroy($im);
}
function VerifyFont($font, $mode = '')
{
$default_fonts = array('Arial', 'Courier', 'Helvetica', 'Times');
if (!in_array($font, $default_fonts))
{
if ($mode)
$this->AddFont($font, 'B', strtolower($font).'b.php');
else
$this->AddFont($font);
}
}
function WriteHTML($html)
{
global $config;
//HTML parser
$html = str_replace("\n",' ',$html);
$a = preg_split('/<(.*)>/U',$html,-1,PREG_SPLIT_DELIM_CAPTURE);
foreach($a as $i=>$e)
{
if($i%2==0)
{
//Text
if($this->HREF)
$this->PutLink($this->HREF,$e);
else
$this->Write((int)$config['pdf_font_size'] / 2.5, $e);
}
else
{
//Tag
if($e[0]=='/')
$this->CloseTag(strtoupper(substr($e,1)));
else
{
//Extract attributes
$a2=explode(' ',$e);
$tag=strtoupper(array_shift($a2));
$attr=array();
foreach($a2 as $v)
if(ereg('^([^=]*)=["\']?([^"\']*)["\']?$',$v,$a3))
$attr[strtoupper($a3[1])]=$a3[2];
$this->OpenTag($tag,$attr);
}
}
}
}
function OpenTag($tag, $attr)
{
global $config;
//Opening tag
if($tag=='B' or $tag=='I' or $tag=='U')
$this->SetStyle($tag,true);
if($tag=='A')
$this->HREF=$attr['HREF'];
if($tag=='BR')
$this->Ln((int)$config['pdf_font_size'] / 2);
}
function CloseTag($tag)
{
//Closing tag
if($tag=='B' or $tag=='I' or $tag=='U')
$this->SetStyle($tag,false);
if($tag=='A')
$this->HREF='';
}
function SetStyle($tag, $enable)
{
//Modify style and select corresponding font
$this->$tag+=($enable ? 1 : -1);
$style='';
foreach(array('B','I','U') as $s)
if($this->$s>0)
$style.=$s;
$this->SetFont('',$style);
}
function PutLink($URL, $txt)
{
global $config;
//Put a hyperlink
$this->SetTextColor(0,0,255);
$this->SetStyle('U',true);
$this->Write((int)$config['pdf_font_size'] / 2, $txt, $URL);
$this->SetStyle('U',false);
$this->SetTextColor(0);
}
/**
* @author Olivier <oliver@fpdf.org>
* @license Freeware
*/
function WordWrap(&$text, $maxwidth)
{
$text = trim($text);
if ($text==='')
return 0;
$space = $this->GetStringWidth(' ');
$lines = explode("\n", $text);
$text = '';
$count = 0;
foreach ($lines as $line)
{
$words = preg_split('/ +/', $line);
$width = 0;
foreach ($words as $word)
{
$wordwidth = $this->GetStringWidth($word);
if ($width + $wordwidth <= $maxwidth)
{
$width += $wordwidth + $space;
$text .= $word.' ';
}
else
{
$width = $wordwidth + $space;
$text = rtrim($text)."\n".$word.' ';
$count++;
}
}
$text = rtrim($text)."\n";
$count++;
}
$text = rtrim($text);
return $count;
}
function SaveFile($filename)
{
FPDF::Output('D', 'videoDB.pdf', $isUTF8=false);
readfile($filename);
}
}
/**
* Return image name for representing the media type
*/
function getMediaImage($mediatype)
{
if (preg_match("/^(DVD([+-]R)?|DivX|CD|VCD|SVCD|VHS|BLU-RAY|AVCHD|HDD|HD-DVD)/i", $mediatype, $matches))
{
$type_image = strtolower($matches[1]).'.png';
}
else $type_image = '';
return $type_image;
}
/**
* Export PDF document
*
* @param string $where WHERE clause for SQL statement
*/
function pdfexport($WHERE)
{
global $config;
$ypos = $config['pdf_font_size']; // Match the font size for proper vertical offset
$page_width = $config['pdf_page_width'];
$margin = $config['pdf_margin'];
$left_margin = $config['pdf_left_margin'];
$right_margin = $config['pdf_right_margin'];
$mediaimg_width = $config['pdf_image_media_width'];
$font_size = $config['pdf_font_size'];
$image_height = $config['pdf_image_height'];
$image_width = $config['pdf_image_width'];
$font_title = $config['pdf_font_title'];
$font_plot = $config['pdf_font_plot'];
$text_length = $config['pdf_text_length'];
$tempfolder = cache_get_folder('');
if ($config['cache_pruning']) cache_prune_folder($tempfolder, 3600, false, false, 'videodb*.pdf');
$filename = $tempfolder.'videodb'.date('His',time()).'.pdf';
// setup pdf class
$pdf = new PDF();
$pdf->Open($filename);
$pdf->VerifyFont($font_title);
$pdf->VerifyFont($font_title, 'B');
$pdf->VerifyFont($font_plot);
$pdf->AddPage();
$pdf->SetRightMargin($right_margin);
// add downscaling
if (array_key_exists('pdf_scale', $config) && $config['pdf_scale'])
{
$pdf->Scale = $config['pdf_scale'];
$pdf->max_width = $config['pdf_image_max_width'];
$pdf->max_height= $config['pdf_image_max_height'];
}
// get data
$result = iconv_array('utf-8', 'iso-8859-1', exportData($WHERE));
$tech = array();
foreach ($result as $row)
{
set_time_limit(300); // rise per movie execution timeout limit if safe_mode is not set in php.ini
$title = $row['title'];
if ($row['subtitle']) $title .= ' - '.$row['subtitle'];
if ($row['diskid'] || $row['mediatype'])
{
$title .= ' [';
if ($row['mediatype']) $title .= $row['mediatype'] . ', ';
if ($row['diskid']) $title .= $row['diskid'];
$title = preg_replace('/, $/', '', $title) . ']';
}
// get drilldown url for image
$imdb = $row['imdbID'];
$link = ($imdb) ? engineGetContentUrl($imdb, engineGetEngine($imdb)) : '';
// title
$pdf->SetFont($font_title, 'B', $font_size);
$pdf->SetXY($left_margin + $image_width + $margin, $ypos);
$pdf->Cell(0, 0, $title, 0,1, 'L',0,$link);
// [muddle] technical details
unset($tech['Y']);
if ($row['year']) {
$tech['Y'] = "Year: ".$row['year'];
}
unset($tech['V']);
if ($row['video_width'] and $row['video_height'])
{
$vw = $row['video_width'];
$vh = $row['video_height'];
$tech['V'] = "Video: ";
if ($vw>1920) {
$tech['V'] .= "UHD ".$vw."x".$vh;
} elseif ($vw>1280) {
$tech['V'] .= "HD 1080p";
} elseif ($vw==1280 or $vh==720) {
$tech['V'] .= "HD 720p";
} elseif ($vw==720 or $vw==704) {
$tech['V'] .= "SD ";
if ($vh==480) {
$tech['V'] .= "NTSC";
} elseif ($vh==576) {
$tech['V'] .= "PAL";
} else {
$tech['V'] .= $vw."x".$vh;
}
} else {
$tech['V'] .= "LORES ".$vw."x".$vh;
}
}
unset($tech['A']);
if ($row['audio_codec']) {
$tech['A'] = "Audio: ".$row['audio_codec'];
}
unset($tech['D']);
if ($row['created']) {
$tech['D'] = "Date: ".$row['created'];
}
$techinfo = implode(", ", $tech);
$pdf->SetFont($font_title, 'B', $font_size-3);
$pdf->SetXY($left_margin + $image_width + $margin, $ypos+ 4);
$pdf->Cell(0, 0, $techinfo, 0,1, 'L',0);
// plot
$plot = leftString($row['plot'], $text_length);
$pdf->SetFont($font_plot, '', $font_size-1);
$pdf->SetXY($left_margin + $image_width + $margin, $ypos+3 +3);
$pdf->SetLeftMargin($left_margin + $image_width + $margin);
$pdf->WriteHTML($plot);
// image
$file = getThumbnail($row['imgurl']);
if (preg_match('/^img.php/', $file)) $file = img();
// image file present?
if ($file)
{
$pdf->Image($file, $left_margin, $ypos-2, $image_width, $image_height, '', $link);
}
// add mediatype image
if ($type_image = getMediaImage($row['mediatype']))
{
$pdf->Image('./images/media/'.$type_image, $page_width - $mediaimg_width - $right_margin, $ypos - 2, $mediaimg_width, 0, '', '');
}
// new position
$ypos += $margin;
if ($file or $plot)
{
$ypos += max($image_height, $font_size);
}
else
{
$ypos += $font_size;
}
if ($ypos > 250)
{
$ypos = $config['pdf_font_size'];
$pdf->AddPage();
}
}
$pdf->SaveFile($filename);
// get rid of temp file
@unlink($filename);
}
?>

View File

@@ -0,0 +1,182 @@
<?php
/**
* Searchquerystring Parser
*
* Parses a search query into it's tokens kann detect + - AND OR NOT Operators
* and Phrases.
*
* @todo remove german errorstrings, maybe handle umlauts and stuff...
*
* @package Search
* @author Andreas Gohr <a.gohr@web.de>
* @author Andreas Götz <cpuidle@gmx.de>
* @version $Id: queryparser.php,v 1.9 2007/12/19 18:42:11 andig2 Exp $
*/
/**
* Querystringparser
*
* Parses a querystring into a datastructure
*
* @param string $query Querystring
* @param string &$errors Stringreference to write errors back
* @return array parsed querytokens
*/
function queryparser($query, &$errors)
{
$query = trim($query);
/*
// filter forbidden characters
if (preg_match('/[^\w \.\(\)"\'*]/',$query))
{
$errors .= "Nicht erlaubte Zeichen wurden ignoriert\n";
$query = preg_replace('/[^\w \.\(\)"\'*]/','',$query);
}
*/
$ops = array();
$struct = array();
$tokens = tokenizer($query);
// look through tokens
while ($current = array_shift($tokens))
{
if (preg_match('/^(AND|OR|NOT)$/i', $current))
{
// token is operator
$ops[] = strtoupper($current);
}
else
{
// token is searchword
if (!count($ops))
{
// empty operator counts as AND
$ops[] = 'AND';
}
// clean invalid operators
$cleanops = cleanoperators($ops, $errors);
// check wildcards
$wild = '';
if (substr($current,0,1) == '*') $wild .= 'l';
if (substr($current, -1) == '*') $wild .= 'r';
$current = str_replace('*', '', $current);
$struct[] = array('ops' => $cleanops,
'token' => $current,
'wildcard' => $wild);
$ops = array();
}
}
return $struct;
}
/**
* Querystring tokenizer
*
* Parse string into array of tokens.
* Honors literal expressions enclosed by "",
* converts +/- to AND and NOT
*
* @param string Querystring
* @return array All tokens of the Strings
*/
function tokenizer($qstring)
{
// replace +/- with AND and NOT
$qstring = ' '.$qstring; // for following regexps
$qstring = preg_replace('/(\s)-(\S)/', '\1NOT \2', $qstring);
$qstring = preg_replace('/(\s)\+(\S)/', '\1AND \2', $qstring);
$qstring = trim($qstring);
$tokens = array();
$current = '';
$sep = '\s';
for ($i=0; $i < strlen($qstring); $i++)
{
$char = $qstring[$i];
// match current separator?
if (preg_match("/$sep/", $char))
{
$current = trim($current);
if (!empty($current) AND ((str_replace('*', '', $current)) != ''))
{
// add non-empty token
$tokens[] = $current;
}
$current = '';
$sep = '\s';
}
// begin literal expression?
elseif ($char == '"')
{
$sep = '"';
}
// normal token character
else
{
$current .= $char;
}
}
// add remaining token
$current = trim($current);
if (!empty($current) AND ((str_replace('*','',$current))!=''))
{
$tokens[] = $current;
}
return $tokens;
}
/**
* Operator cleaning
*
* removes illogical operator combinations...
*
* @param array Operators
* @param string Stringreference to write errors back
* @return string cleaned Operators
*/
function cleanoperators($ops, &$errors)
{
$newops = array();
// make unique
$ops = array_unique($ops);
// sort
if (in_array('AND', $ops)) $newops[] = 'AND';
if (in_array('OR', $ops)) $newops[] = 'OR';
if (in_array('NOT', $ops)) $newops[] = 'NOT';
// join
$opstr = join(' ', $newops);
// clean unnormal conditions
if (strstr($opstr, 'AND OR'))
{
$errors .= "Die logische Verknüpfung 'AND OR' ist nicht erlaubt und wurde in 'OR' umgewandelt.\n";
$opstr = str_replace('AND OR', 'OR', $opstr);
}
if (strstr($opstr, 'OR NOT'))
{
$errors .= "Die logische Verknüpfung 'OR NOT' ist nicht erlaubt und wurde in 'AND' umgewandelt.\n";
$opstr = str_replace('OR NOT', 'AND', $opstr);
}
if ($opstr == 'NOT')
{
$opstr = 'AND NOT';
}
return $opstr;
}

59
videodb/core/security.php Normal file
View File

@@ -0,0 +1,59 @@
<?php
/**
* Security functions
*
* @package Core
* @author Andreas Goetz <cpuidle@gmx.de>
* @author tREXX <www.trexx.ch>
* @version $Id: security.php,v 1.2 2008/01/05 13:50:58 andig2 Exp $
*/
/**
* Allow these tags
*/
$allowedTags = '<h1><h2><h3><h4><b><strong><i><a><ol><ul><li><pre><hr><blockquote>';
/**
* Disallow these attributes/prefix within a tag
*/
$stripAttrib = 'javascript:|onclick|ondblclick|onmousedown|onmouseup|onmouseover|'.
'onmousemove|onmouseout|onkeypress|onkeydown|onkeyup';
/**
* @return string
* @param string
* @desc Strip forbidden attributes from a tag
*/
function removeEvilAttributes($tagSource)
{
global $stripAttrib;
return stripslashes(preg_replace("/$stripAttrib/i", 'forbidden', $tagSource));
}
/**
* @return string
* @param string
* @desc Strip forbidden attributes from an array of matches for an expression like (<)(.*?)(>)
*/
function _callbackRemoveEvilAttributes($matches)
{
return $matches[1] . removeEvilAttributes($matches[2]) . $matches[3];
}
/**
* @return string
* @param string
* @desc Strip forbidden tags and delegate tag-source check to removeEvilAttributes()
*/
function removeEvilTags($source)
{
global $allowedTags;
if (!is_null($source))
{
$source = strip_tags($source, $allowedTags);
return preg_replace_callback('/(<)(.*?)(>)/i', "_callbackRemoveEvilAttributes", $source);
}
return $source;
}
?>

69
videodb/core/session.php Normal file
View File

@@ -0,0 +1,69 @@
<?php
/**
* Session functions
*
* Moved all session functions into one file,
* include this where session starting might be required
*
* @package Core
* @author Andreas Goetz <cpuidle@gmx.de>
* @version $Id: session.php,v 1.13 2008/02/28 20:01:17 andig2 Exp $
*/
// start session
session_start();
/**
* Get session value or specified default
*/
function session_get($varname, $default=null)
{
if (isset($_SESSION['vdb'][$varname]))
{
return $_SESSION['vdb'][$varname];
}
return $default;
}
/**
* Set session value or specified default
*/
function session_set($varname, $value)
{
$_SESSION['vdb'][$varname] = $value;
}
/**
* Upsert session value with current value of global variable or specified default
*/
function session_default($varname, $default=null)
{
global $$varname;
if (!isset($$varname))
{
$$varname = (isset($_SESSION['vdb'][$varname])) ? $_SESSION['vdb'][$varname] : $default;
}
$_SESSION['vdb'][$varname] = $$varname;
}
/**
* get session_default for owner
*
* basically this only executes the extra query when the global $owner is not set and also
* not available in session data. only then we need the hasAny check. if the global is set
* or the global is not set but the session is then session_default() will fix both those
* cases. put into a single function because it gets called from multiple files.
*/
function session_default_owner()
{
global $owner, $lang;
if (!isset($owner) && !isset($_SESSION['vdb']['owner'])) {
$hasAny = runSQL('SELECT COUNT(*) AS num FROM '.TBL_DATA.' WHERE '.TBL_DATA.'.owner_id = ' . get_current_user_id());
$hasAny = ($hasAny && isset($hasAny[0]['num']) && $hasAny[0]['num'] > 0);
$default = ($hasAny ? get_username(get_current_user_id()) : $lang['filter_any']);
return session_default('owner', $default);
}
return session_default('owner');
}

356
videodb/core/setup.core.php Normal file
View File

@@ -0,0 +1,356 @@
<?php
/**
* Functions for config options
*
* @package Core
* @author Andreas Gohr <a.gohr@web.de>
* @author Andreas Götz <cpuidle@gmx.de>
* @version $Id: setup.core.php,v 1.12 2013/03/16 10:10:07 andig2 Exp $
*/
require_once './core/functions.php';
require_once './core/custom.php';
require_once './core/output.php';
$SETUP_GLOBAL = array('language', 'autoid', 'mediadefault', 'langdefault', 'acclangbrowser',
'filterdefault', 'showtv', 'orderallbydisk', 'removearticles',
'localnet', 'IMDBage', 'thumbnail',
'castcolumns', 'template', 'languageflags', 'custom1',
'custom2', 'custom3', 'custom4', 'custom1type',
'custom2type', 'custom3type', 'custom4type', 'enginedefault',
'proxy_host', 'proxy_port', 'actorpics', 'thumbAge', 'listcolumns',
'shownew', 'imdbBrowser', 'multiuser', 'denyguest', 'adultgenres',
'pageno', 'showtools', 'showcasttoggle', 'browse_include_title');
$SETUP_QUICK = array('template');
$SETUP_USER = array('language', 'mediadefault', 'langdefault', 'acclangbrowser', 'filterdefault',
'showtv', 'orderallbydisk', 'template', 'languageflags',
'listcolumns', 'castcolumns', 'shownew', 'pageno', 'removearticles',
'showcasttoggle', 'browse_include_title');
/**
* Build config options array
*
* @param boolean $isprofile Determines if user-specific options are to be displayed
*
* @return array associative array of config options
*/
function setup_mkOptions($isprofile = false)
{
global $config, $lang;
// built list of setup options
$setup = array();
// isprofile, name, type (text|boolean|dropdown|special|link), data, set, helphl, helptxt
$setup[] = setup_addSection('opt_general');
$setup[] = setup_addOption($isprofile, 'language', 'dropdown', setup_getLanguages(), null, $lang['help_langn'], $lang['help_lang']);
$option = setup_addOption($isprofile, 'template', 'dropdown', setup_getTemplates($thumbs));
$option['thumbs'] = $thumbs;
$setup[] = $option;
$setup[] = setup_addOption($isprofile, 'listcolumns', 'text');
$setup[] = setup_addOption($isprofile, 'castcolumns', 'text');
$setup[] = setup_addOption($isprofile, 'autoid', 'boolean');
$setup[] = setup_addOption($isprofile, 'orderallbydisk', 'boolean');
$setup[] = setup_addOption($isprofile, 'mediadefault', 'dropdown', setup_getMediatypes());
$setup[] = setup_addOption($isprofile, 'langdefault', 'text');
$setup[] = setup_addOption($isprofile, 'acclangbrowser', 'boolean');
$setup[] = setup_addOption($isprofile, 'filterdefault', 'dropdown', array('all'=>$lang['radio_all'], 'unseen'=>$lang['radio_unseen'], 'new'=>$lang['radio_new'], 'wanted'=>$lang['radio_wanted']));
$setup[] = setup_addOption($isprofile, 'showtv', 'boolean');
$setup[] = setup_addOption($isprofile, 'shownew', 'text');
$setup[] = setup_addOption($isprofile, 'pageno', 'text');
$setup[] = setup_addOption($isprofile, 'languageflags', 'special', out_languageflags($config['languages']));
$setup[] = setup_addOption($isprofile, 'removearticles', 'boolean');
$setup[] = setup_addOption($isprofile, 'adultgenres', 'multi', setup_getGenres(), @explode('::', $config['adultgenres']));
$setup[] = setup_addOption($isprofile, 'showtools', 'boolean');
$setup[] = setup_addOption($isprofile, 'showcasttoggle', 'boolean');
$setup[] = setup_addOption($isprofile, 'browse_include_title', 'dropdown', array('none' => $lang['none'], 'top' => $lang['top'], 'bottom' => $lang['bottom'], 'both' => $lang['both']));
if (!$isprofile) $setup[] = setup_addSection('opt_custom');
$setup[] = setup_addOption($isprofile, 'custom', 'special', setup_mkCustoms(), 'custom', $lang['help_customn'], $lang['help_custom']);
if (!$isprofile) $setup[] = setup_addSection('opt_engines');
$setup[] = setup_addOption($isprofile, 'enginedefault', 'dropdown', setup_getEngines($config['engines']), null , $lang['help_defaultenginen'], $lang['help_defaultengine']);
foreach ($config['engines'] as $engine => $meta)
{
$title = $meta['name'];
if (array_key_exists($engine,$config['engine'])) {$enabled = $config['engine'][$engine];} else {$enabled = null;}
$helptext = sprintf($lang['help_engine'], $title);
if (array_key_exists('help_engine' . $engine, $lang)) {$helptext .= ' ' . $lang['help_engine' . $engine];}
if (!array_key_exists('stable', $meta) || $meta['stable'] == 0) {$helptext .= ' ' . $lang['help_engexperimental'];}
$setup[] = setup_addOption($isprofile, 'engine'.$engine, 'boolean', null, $enabled, $title, $helptext);
// add engine-specific options
if (array_key_exists('config', $meta) && is_array($meta['config']))
{
foreach ($meta['config'] as $setting)
{
// NOTE: check setup_additionalSettings if you change the option naming
if (is_array($setting['values']))
$setup[] = setup_addOption($isprofile, $engine.$setting['opt'],
'dropdown', $setting['values'], null, $setting['name'], $setting['desc']);
else
$setup[] = setup_addOption($isprofile, $engine.$setting['opt'],
'text', null, null, $setting['name'], $setting['desc']);
}
}
}
if (!$isprofile) {$setup[] = setup_addSection('opt_security');}
$setup[] = setup_addOption($isprofile, 'localnet', 'text');
$setup[] = setup_addOption($isprofile, 'multiuser', 'boolean');
$setup[] = setup_addOption($isprofile, 'denyguest', 'boolean');
$setup[] = setup_addOption($isprofile, 'usermanager', 'link', 'users.php', 'usermanager');
$setup[] = setup_addOption($isprofile, 'proxy_host', 'text');
$setup[] = setup_addOption($isprofile, 'proxy_port', 'text');
if (!$isprofile) {$setup[] = setup_addSection('opt_caching');}
$setup[] = setup_addOption($isprofile, 'thumbnail', 'boolean');
$setup[] = setup_addOption($isprofile, 'imdbBrowser', 'boolean');
$setup[] = setup_addOption($isprofile, 'IMDBage', 'text');
$setup[] = setup_addOption($isprofile, 'actorpics', 'boolean');
$setup[] = setup_addOption($isprofile, 'thumbAge', 'text');
// clean empty entries
for ($i = count($setup); $i > 0; $i--)
{
if (empty($setup[$i]['name']) && empty($setup[$i]['group'])) unset($setup[$i]);
}
return $setup;
}
/**
* Add engine-specific config options for saving
*/
function setup_additionalSettings()
{
global $config, $SETUP_GLOBAL;
foreach ($config['engines'] as $engine => $meta)
{
// add engine-specific options
if (array_key_exists('config', $meta) && is_array($meta['config']))
{
foreach ($meta['config'] as $setting)
{
$SETUP_GLOBAL[] = $engine.$setting['opt'];
}
}
}
}
/**
* Add a new section to the config options array
*
* @param array $setup The config array
* @param string $section Name of the new section
*/
function setup_addSection($section)
{
$option['group'] = $section;
return $option;
}
/**
* Adds an entry for the config option array
*
* returns NULL on global options if $isprofile is true
* so global options will not be added to user profile settings
*
* @param array $setup The config array
* @param boolean $isprofile Do we prepare a profile array?
* @param string $name Name of the config option
* @param string $type Type of option (text|boolean|dropdown|special|link)
* @param string $data Current value of this option
* @param string $set Default value of this option
* @param string $hl Help text headline
* @param string $help Help text
*/
function setup_addOption($isprofile, $name, $type,
$data='', $set=NULL, $hl=NULL, $help=NULL)
{
global $config, $lang;
global $SETUP_USER;
// user-specific setting?
$isuser = in_array($name, $SETUP_USER);
if ($isprofile and !$isuser) return;
$option['isuser'] = $isuser;
$option['name'] = $name;
$option['type'] = $type;
$option['data'] = $data;
$option['set'] = ($set) ? $set : $config[$name];
$option['hl'] = ($hl) ? $hl : $lang['help_'.$name.'n'];
$option['help'] = ($help) ? $help : $lang['help_'.$name];
return $option;
}
/**
* Find available languages
*/
function setup_getLanguages()
{
if ($dh = opendir('language'))
{
while (($file = readdir($dh)) !== false)
{
if (preg_match("/(.*)\.php$/", $file, $matches))
{
$languages[$matches[1]] = $matches[1];
}
}
closedir($dh);
}
return $languages;
}
/**
* Find available templates/styles
* Extended to search for template screenshots
*
* @author Andreas Götz <cpuidle@gmx.de>
*/
function setup_getTemplates(&$screenshots)
{
$screenshots = array();
if ($dh = @opendir('templates'))
{
while (($file = readdir($dh)) !== false)
{
if (preg_match("/^\./", $file)) continue;
if (is_dir('templates/'.$file))
{
$template = 'templates/'.$file;
if ($dh2 = opendir($template))
{
$style_name = '';
while (($style = readdir($dh2)) !== false)
{
if (preg_match("/(.*)\.css$/", $style, $matches))
{
$thumb = $template.'/screenshot_'.$matches[1].'.jpg';
if (file_exists($thumb))
{
$screenshots[] = array('name' => "$file::".$matches[1], 'img' => $thumb);
}
elseif (empty($style_name))
{
// remember first style found
$style_name = $matches[1];
}
$templates[$file.'::'.$matches[1]] = $file.' ('.$matches[1].')';
}
}
closedir($dh2);
if ($style_name)
{
$thumb = $template.'/screenshot.jpg';
if (file_exists($thumb))
{
$screenshots[] = array('name' => "$file::$style_name", 'img' => $thumb);
}
}
}
}
}
closedir($dh);
}
return $templates;
}
/**
* Mediatypes
*/
function setup_getMediatypes()
{
$SELECT = 'SELECT id, name
FROM '.TBL_MEDIATYPES.'
ORDER BY name';
$result = runSQL($SELECT);
return array_associate($result, 'id', 'name');
}
/**
* Genres
*/
function setup_getGenres()
{
$SELECT = 'SELECT id, name
FROM '.TBL_GENRES.'
ORDER BY name';
$result = runSQL($SELECT);
return array_associate($result, 'id', 'name');
}
/**
* Get list of engines for default engine selection
*/
function setup_getEngines($engines_ary)
{
$engines = array();
foreach ($engines_ary as $engine => $meta)
{
if (engine_get_capability($engine, 'movie')) $engines[$engine] = $meta['name'];
}
return $engines;
}
/**
* Prepare customfields
*/
function setup_mkCustoms()
{
global $config;
global $allcustomtypes;
$setup_custom = '';
for ($i=1; $i<5; $i++)
{
$setup_custom .= $i.'. <input type="text" size="20" name="custom'.$i.'" id="custom'.$i.'" value="'.formvar($config['custom'.$i]).'"/>';
$setup_custom .= '<select name="custom'.$i.'type">';
foreach($allcustomtypes as $ctype)
{
$selected = ($ctype == $config['custom'.$i.'type']) ? ' selected="selected"' : '';
$setup_custom .= '<option value="'.$ctype.'"'.$selected.'>'.$ctype.'</option>';
}
$setup_custom .= '</select>';
$setup_custom .= "<br />\n";
}
return $setup_custom;
}
/**
* Update session variables with configuration values
*
* @author Andreas Goetz
*/
function update_session()
{
global $listcolumns, $showtv;
if ($listcolumns) $_SESSION['vdb']['listcolumns'] = $listcolumns;
if ($showtv) $_SESSION['vdb']['showtv'] = $showtv;
}

612
videodb/core/template.php Normal file
View File

@@ -0,0 +1,612 @@
<?php
/**
* Template functions
*
* These functions prepare the data for assignment to the template engine
*
* @todo replace additional assignments of config options by using $config
*
* @package Core
* @author Andreas Gohr <a.gohr@web.de>
* @author Andreas Goetz <cpuidle@gmx.de>
* @author Chinamann <chinamann@users.sourceforge.net>
* @version $Id: template.php,v 1.70 2013/03/21 16:27:57 andig2 Exp $
*/
require_once './core/session.php';
require_once './core/output.php';
require_once './core/genres.php';
require_once './core/functions.php';
require_once './engines/engines.php';
/**
* Display template with standard header and footer
*/
function tpl_display_show($template, $flush = true)
{
smarty_display('header.tpl');
if ($flush) flush();
smarty_display($template);
smarty_display('footer.tpl');
}
/**
* Display page using templates
* If page content is unmodified, return HTTP 304 Not modified
*
* @param string $template Template name for main content
*/
function tpl_display($template)
{
global $config;
// caching enabled?
if ($config['http_caching'])
{
require_once('./core/httpcache.php');
httpCacheCaptureStart();
}
tpl_display_show($template, !$config['http_caching']);
if ($config['http_caching'])
{
httpCacheOutput($template, httpCacheCaptureEnd());
}
}
/**
* Prepare standard page templates
*/
function tpl_page($help = '', $title = '')
{
tpl_language();
tpl_header($help, $title);
tpl_footer();
}
/**
* Assigns language strings and config options to the smarty engine
*/
function tpl_language()
{
global $smarty, $lang, $config;
$smarty->assign('lang', $lang);
$smarty->assign('config', $config);
}
/**
* Assigns the header urls to the smarty engine
*
* @param string $help The helpfile to display (optional, without extension)
* @param string $title The text to add to html <title> tag (optional, will be html-encoded)
*/
function tpl_header($help = '', $title = '')
{
global $smarty, $lang, $config;
global $id, $diskid;
// viewing is only availble if autorized or public access
if (auth_check(false))
{
$header['browse'] = 'index.php';
if (check_permission(PERM_READ, PERM_ANY))
{
$header['random'] = 'show.php';
$header['search'] = 'search.php';
}
$header['stats'] = 'stats.php';
if ($config['imdbBrowser']) $header['trace'] = 'trace.php';
$header['help'] = 'help.php';
if ($help) $header['help'] .= '?page='.$help.'.html';
}
// editing is only available in local network
if (localnet())
{
if (check_permission(PERM_WRITE, PERM_ANY))
{
$header['new'] = 'edit.php';
if ($config['showtools']) $header['contrib'] = 'contrib.php';
}
if (check_permission(PERM_ADMIN)) $header['setup'] = 'setup.php';
// edit or show?
if ($id)
{
if (check_videopermission(PERM_WRITE, $id)) $header['edit'] = 'edit.php?id='.$id;
if (!preg_match('/show.php$/', $_SERVER['PHP_SELF']))
{
$header['view'] = 'show.php?id='.$id;
}
if (check_videopermission(PERM_WRITE, $id)) $header['del'] = 'delete.php?id='.$id;
}
if (check_permission(PERM_WRITE, PERM_ANY))
{
$header['borrow'] = 'borrow.php';
if (isset($diskid)) $header['borrow'] .= '?diskid='.$diskid;
}
}
// multiuser settings
if ($config['multiuser'])
{
$header['login'] = 'login.php';
// logged in?
if (!empty($_COOKIE['VDBusername']) && $_COOKIE['VDBuserid'] != $config['guestid'])
{
$header['profile'] = 'profile.php';
$smarty->assign('loggedin', $_COOKIE['VDBusername']);
}
else
{
// make sure anonymous users don't get access to trace for security reasons
unset($header['trace']);
}
if (check_permission(PERM_ADMIN)) $header['users'] = 'users.php';
}
// determine active tab
if (preg_match('/(\w+)\.php/', $_SERVER['PHP_SELF'], $m))
{
$tab = strtolower($m[1]);
switch ($tab)
{
case 'show':
$header['request_uri'] = $_SERVER['REQUEST_URI'];
case 'edit':
if (!empty($id)) $header['active'] = $tab;
// uncomment this if you want the 'Browse' tab to remember last visited movie
// { ... $smarty->assign('browseid', $_REQUEST['id']); }
else $header['active'] = ($tab == 'show') ? 'random' : 'new';
break;
default:
/* legacy version
$translate = array('index' => 'browse', 'users' => 'setup', 'permissions' => 'setup', 'delete' => 'show');
*/
$translate = array('index' => 'browse', 'permissions' => 'users', 'delete' => 'show');
if (in_array($tab, array_keys($translate)))
{
$tab = $translate[$tab];
}
$header['active'] = $tab;
}
}
// breadcrumbs
$breadcrumbs = session_get('breadcrumbs', array());
$smarty->assign('breadcrumbs', $breadcrumbs);
if (!is_null($title))
{
$smarty->assign('title', htmlspecialchars($title));
}
else
{
$smarty->assign('title', "");
}
$smarty->assign('header', $header);
$smarty->assign('style', $config['style']);
$smarty->assign('langcode', $config['language']);
}
/**
* Assigns the filter options to the smarty engine
*/
function tpl_filters($filter, $showtv)
{
global $smarty, $lang;
global $filter_expr;
global $owner, $mediatype;
global $config;
// build filter array
foreach ($filter_expr as $flt => $regex)
{
$filters[$flt] = ($flt == "NUM") ? "#" : $flt;
}
$filters['all'] = $lang['radio_all'];
$filters['unseen'] = $lang['radio_unseen'];
$filters['new'] = $lang['radio_new'];
/*
# removed as of 4.0 in favour of media type filter
$filters['wanted'] = $lang['radio_wanted'];
*/
$smarty->assign('filters', $filters);
$smarty->assign('filter', $filter);
$smarty->assign('showtv', $showtv);
// create owner selectbox
$smarty->assign('owners', out_owners(array($lang['filter_any'] => $lang['filter_any']), PERM_READ));
if (!$owner) $owner = $lang['filter_any']; //!! default owner hack
$smarty->assign('owner', $owner);
// create mediatype selectbox
$smarty->assign('mediafilter', out_mediatypes(array(-2 => $lang['filter_any'], -1 => $lang['filter_available'])));
if (!$mediatype) $mediatype = session_get('mediafilter'); //!! default media type hack
$smarty->assign('mediatype', $mediatype);
// create sorting selectbox
// Sorting is disabled when ordering by diskid is enabled
if(!$config['orderallbydisk']) {
$smarty->assign('order_options', array(-1 => $lang['title'], 1 => $lang['rating'], 2 => $lang['date']));
if(!isset($order)) $order = session_get('order');
$smarty->assign('order', $order);
}
// enable dynamic columns in list view
$smarty->assign('listcolumns', session_get('listcolumns'));
}
function adultcheck_for_video($video)
{
return adultcheck($video["id"]);
}
/**
* Assigns the searchresults/browselist to the smarty engine
*
* @param array indexed array containing the item data
*/
function tpl_list($list)
{
global $smarty, $config;
global $listcolumns;
if(!$list)
{
$smarty->assign('totalresults', 0);
return;
}
for ($i=0; $i < count($list); $i++)
{
// setup imgurls
$list[$i]['imgurl'] = ($config['thumbnail']) ? getThumbnail($list[$i]['imgurl']) : '';
// check for flagfile
$languages = $list[$i]['language'];
$flagfile = img('flags/'.$languages.'.gif');
if (file_exists($flagfile))
{
// one langage
$list[$i]['flagfile'][$languages] = $flagfile;
$list[$i]['language'] = array($list[$i]['language']);
}
else
{
// multiple languages
$langary = preg_split('/,\s*/', $languages);
$list[$i]['language'] = $langary;
// assign them all
foreach ($langary as $languagepart)
{
$flagfile = img('flags/'.$languagepart.'.gif');
if (file_exists($flagfile))
{
$list[$i]['flagfile'][$languagepart] = $flagfile;
}
}
}
// is this file editable?
if (localnet())
{
$list[$i]['editable'] = ($config['multiuser']) ?
check_permission(PERM_WRITE, $list[$i]['owner_id']) : true;
}
else
{
$list[$i]['editable'] = false;
}
/*
uncomment this to allow display of rating in the 'Browse' tab
require_once 'custom.php';
customfields($list[$i], 'out');
*/
}
// do adultcheck
if (is_array($list))
{
$list = array_filter($list, "adultcheck_for_video");
}
// enable dynamic columns in list view
$smarty->assign('listcolumns', session_get('listcolumns'));
$smarty->assign('list', $list);
// show total number of movies in footer
$smarty->assign('totalresults', count($list));
}
/**
* Assigns debug infos and version to the smarty engine
*/
function tpl_footer()
{
global $smarty, $config, $SQLtrace;
if ($config['debug'])
{
$out = $config;
$out['db_password'] = '***';
$session = $_SESSION['vdb'];
$session['db_password'] = '***';
ob_start();
print '<pre>';
dump($SQLtrace);
dump($out);
dump($session);
print '</pre>';
# phpinfo();
$debug = ob_get_contents();
ob_end_clean();
$smarty->assign('DEBUG', $debug);
}
$smarty->assign('version', VERSION);
}
/**
* Function combines multiple actor thumbnail queries into single SQL query
*/
function get_actor_thumbnails_batched(&$actors)
{
if (!count($actors)) return;
$ids = "'".join("','", array_map('escapeSQL', array_column($actors, 'id')))."'";
$SQL = 'SELECT actorid, name, imgurl, UNIX_TIMESTAMP(NOW()) - UNIX_TIMESTAMP(checked) AS cacheage
FROM '.TBL_ACTORS.' WHERE actorid IN ('.$ids.')';
$result = runSQL($SQL);
$result = array_associate($result, 'actorid');
// loop over actors from full-text field
foreach ($actors as $idx => $actor)
{
// check for actor thumbnail
$batch_result = null;
if (array_key_exists($actor['id'], $result))
{
$batch_result = $result[$actor['id']];
}
if ($batch_result)
{
$actors[$idx]['imgurl'] = get_actor_image_from_cache($batch_result, $actor['name'], $actor['id']);
}
else
{
$actors[$idx]['imgurl'] = getActorThumbnail($actor['name'], $actor['id'], false);
}
}
}
/**
* Convert textbox/db presentation into actors array
*/
function split_cast_array(&$actor, $key)
{
$ary = explode('::', $actor);
$actor = array();
$actor['name'] = $ary[0];
$actor['id'] = $ary[2];
$actor['roles'] = preg_split('[^</]', $ary[1]);
}
/**
* Converts plain cast data into array of actors with thumbnails
*
* @author Andreas Goetz <cpuidle@gmx.de>
*/
function prepare_cast($cast)
{
global $config;
// convert text represenatation into array
$actors = array_filter(preg_split("/\r?\n/", trim($cast)));
// reformat roles
$actors = preg_replace('/\((.*?)\)/', '<small>($1)</small>', $actors);
array_walk($actors, 'split_cast_array');
// check for actor thumbnails
if ($config['actorpics']) get_actor_thumbnails_batched($actors);
// loop over actors from full-text field
foreach ($actors as $idx => $actor)
{
$actors[$idx]['imdburl'] = engineGetActorUrl($actor['name'], $actor['id'], engineGetActorEngine($actor['id']));
// check for actor thumbnail
# if ($config['actorpics']) $actor['imgurl'] = getActorThumbnail($actor['name'], $actor['id']);
}
return $actors;
}
/**
* Assigns the videoinfos to the smarty engine
*
* @param array associative array containing the item data
*/
function tpl_show($video)
{
global $smarty, $config;
// imageurl
$video['imgurl'] = getThumbnail($video['imgurl'], $video['title']);
// make soft linebreaks:
$video['filename'] = preg_replace('/(_|\.|-)/', '$1<wbr />', $video['filename']);
// split comma-separated countries, prevent empty array
$video['country'] = preg_split('/,\s*/', $video['country'], -1, PREG_SPLIT_NO_EMPTY);
// split comma-separated multiple languages, prevent empty array
$video['language'] = preg_split('/,\s*/', $video['language'], -1, PREG_SPLIT_NO_EMPTY);
// humanreadable filesize:
$video['filesize'] = round($video['filesize']/(1024*1024), 2);
// break plot and comment
$video['plot'] = nl2br($video['plot']);
$video['comment'] = nl2br($video['comment']);
// cast
$smarty->assign('cast_toggle', $config['showcasttoggle']);
$show_cast = true;
if ($config['showcasttoggle'])
{
$show_cast = (isset($_GET['show_cast']) && $_GET['show_cast'] == '1');
}
$smarty->assign('show_cast', $show_cast);
$video['cast'] = [];
if ($show_cast)
{
$video['cast'] = prepare_cast($video['actors']);
}
// prepare the custom fields
customfields($video, 'out');
// hide owner if not using multi-user
if (!$config['multiuser']) unset($video['owner']);
// get drilldown url for image
if ($video['imdbID'])
{
require_once './engines/engines.php';
$smarty->assign('link', engineGetContentUrl($video['imdbID'], engineGetEngine($video['imdbID'])));
}
// add episodes information
if (array_key_exists('episodes', $video) && is_array($video['episodes']))
{
// allow multiple columns
$smarty->assign('listcolumns', session_get('listcolumns'));
}
$smarty->assign('castcolumns', $config['castcolumns']);
$smarty->assign('video', $video);
// get genre ids and names
$smarty->assign('genres', getItemGenres($video['id'], true));
// make engines available
$smarty->assign('engines', $config['engine']);
// allow XML export
foreach (array('xls','pdf','xml') as $export)
{
if ($config[$export]) $smarty->assign($export, 'show.php?id='.$video['id'].'&amp;');
}
// new-style way of exporting
// $smarty->assign('exports', listExports('show.php?id='.$video['id'].'&amp;'));
}
/**
* Assigns the videoinfos to the smarty engine
*/
function tpl_edit($video)
{
global $smarty, $config, $lang;
// create a form ready quoted version for each value
foreach (array_keys($video) as $key)
{
$video['q_'.$key] = formvar($video[$key]);
}
// use custom function for language
$video['f_language'] = custom_language_input('language', $video['language']);
// create mediatype selectbox
$smarty->assign('mediatypes', out_mediatypes());
if (!isset($video['mediatype'])) $video['mediatype'] = $config['mediadefault'];
// prepare the custom fields
customfields($video, 'in');
if ($config['multiuser'])
{
$smarty->assign('owners', out_owners(array('0' => ''), (check_permission(PERM_ADMIN)) ? false : PERM_WRITE, true));
}
// item genres
if (array_key_exists('id', $video))
{
$item_genres = getItemGenres($video['id']);
}
else
{
$item_genres = array();
}
// new-style
$smarty->assign('genres', out_genres2($item_genres));
#dlog(out_genres2($item_genres));
#dlog($item_genres);
// classic
$smarty->assign('genreselect', out_genres($item_genres));
// assign data
$smarty->assign('video', $video);
// get drilldown url for visit link
if (array_key_exists('imdbID', $video))
{
require_once './engines/engines.php';
$engine = engineGetEngine($video['imdbID']);
$smarty->assign('link', engineGetContentUrl($video['imdbID'], $engine));
$smarty->assign('engine', $engine);
}
/*
// populate autocomplete boxes
$smarty->assign('audio_codecs', array_column(runSQL('SELECT DISTINCT audio_codec FROM '.TBL_DATA.' WHERE audio_codec IS NOT NULL'), 'audio_codec'));
$smarty->assign('video_codecs', array_column(runSQL('SELECT DISTINCT video_codec FROM '.TBL_DATA.' WHERE video_codec IS NOT NULL'), 'video_codec'));
*/
$smarty->assign('lookup', array('0' => $lang['radio_look_ignore'],
'1' => $lang['radio_look_lookup'],
'2' => $lang['radio_look_overwrite']));
// needed for ajax image lookup
$smarty->assign('engines', $config['engines']);
}
/**
* Prepare lookup template
*/
function tpl_lookup($find, $engine, $searchtype)
{
global $smarty, $config;
$find = trim($find);
$smarty->assign('find', $find);
$smarty->assign('q_find', formvar($find));
$smarty->assign('engine', $engine);
$tpl = array();
foreach (engine_get_capable_engines($searchtype) as $eng => $enabled)
{
// url- make sure this is non-unicode
$tpl[$eng]['url'] = 'lookup.php?find='.urlencode(utf8_smart_decode($find)).'&engine='.$eng.'&searchtype='.$searchtype;
// title
$tpl[$eng]['name'] = $config['engines'][$eng]['name'];
}
$smarty->assign('engines', $tpl);
}
?>

459
videodb/core/xls.php Normal file
View File

@@ -0,0 +1,459 @@
<?php
/**
* XLS Export functions
*
* Allows exporting movies to an Excel list
* Requires Spreadsheet_Excel_Writer libaray (http://pear.php.net)
*
* @package Core
* @link http://pear.php.net/package/Spreadsheet_Excel_Writer
* @author Chinamann <chinamann@users.sourceforge.net>
* @author Andreas Götz <cpuidle@gmx.de>
* @version $Id: xls.php,v 1.8 2008/01/05 13:50:29 andig2 Exp $
*/
require_once './core/functions.php';
require_once './core/export.core.php';
require_once './engines/engines.php';
#error_reporting(E_ALL^E_NOTICE);
require_once 'vendor/autoload.php';
/**
* Export PDF document
*
* @param string $where WHERE clause for SQL statement
*/
function xlsexport($WHERE)
{
global $config, $lang;
$text_length = 256-3;
// videodb context dir
$context_dir = preg_replace('/^(.*)\/.*?$/','\\1',$_SERVER["SCRIPT_FILENAME"]);
// array of temp files wich have to be deleted if workbook is closed
$del_list = array();
// make shure we have list with extra fields, even if empty
$extra_fields = array_map('trim', explode(",", $config['xls_extra_fields']));
// Creating a workbook
$workbook = new Spreadsheet_Excel_Writer();
$workbook->setCustomColor(12, 192,192,192); // Headline
$workbook->setCustomColor(13, 255,255,200); // Seen
$workbook->setCustomColor(14, 255,220,220); // Lent
//$workbook->setCustomColor(15, 0,0,0); // Test
// sending HTTP headers
$outputFilename = ($config['xls_output_filename']) ? $config['xls_output_filename'] : 'VideoDB';
$workbook->send($outputFilename.'.xls');
// Creating a worksheet
$sheetTitle = ($config['xls_sheet_title']) ? $config['xls_sheet_title'] : 'VideoDB';
$worksheet =& $workbook->addWorksheet($sheetTitle);
// format templates
$alignLeftFormatNormal =& $workbook->addFormat();
$alignLeftFormatLent =& $workbook->addFormat(array('Pattern' => 1));
$alignLeftFormatLent -> setFGColor(14);
$alignRightFormatNormal =& $workbook->addFormat(array('Align' => 'right'));
$alignRightFormatLent =& $workbook->addFormat(array('Align' => 'right', 'Pattern' => 1));
$alignRightFormatLent -> setFgColor(14);
$alignCenterFormatNormal =& $workbook->addFormat(array('Align' => 'center'));
$alignCenterFormatLent =& $workbook->addFormat(array('Align' => 'center', 'Pattern' => 1));
$alignCenterFormatLent -> setFgColor(14);
$titleFormatNormal =& $workbook->addFormat(array('Bold' => 1));
$titleFormatUnseen =& $workbook->addFormat(array('Bold' => 1, 'Pattern' => 1));
$titleFormatUnseen -> setFgColor(13);
$titleFormatLent =& $workbook->addFormat(array('Bold' => 1, 'Pattern' => 1));
$titleFormatLent -> setFgColor(14);
$plotFormatNormal =& $workbook->addFormat(array('Align' => 'top'));
$plotFormatNormal -> setTextWrap();
$plotFormatLent =& $workbook->addFormat(array('Align' => 'top','Pattern' => 1));
$plotFormatLent -> setTextWrap();
$plotFormatLent -> setFgColor(14);
$headlineFormat =& $workbook->addFormat(array('Bold' => 1, 'Align' => 'center', 'Pattern' => 1));
$headlineFormat ->setFgColor(12);
$rowindex = 0;
$columnindex = 0;
if ($config['xls_show_headline'])
{
$worksheet->setRow(0, 30);
$rowindex++;
}
// get data (see http://pear.php.net/bugs/bug.php?id=1572)
$result = iconv_array('utf-8', 'iso-8859-1', exportData($WHERE));
foreach ($result as $row)
{
$columnindex = 0;
set_time_limit(300); // rise per movie execution timeout limit if safe_mode is not set in php.ini
if (!empty($row['lentto']) && $config['xls_mark_lent']) {
$alignLeftFormat = $alignLeftFormatLent;
$alignCenterFormat = $alignLeftFormatLent;
$alignRightFormat = $alignLeftFormatLent;
}
else
{
$alignLeftFormat = $alignLeftFormatNormal;
$alignCenterFormat = $alignLeftFormatNormal;
$alignRightFormat = $alignLeftFormatNormal;
}
$worksheet->setRow($rowindex, 15, $alignLeftFormat);
foreach ($extra_fields as $field)
{
$isNote = false;
$walks = 1;
if (preg_match('/(.+)\((.+)\)/',$field,$matches))
{
$field = trim($matches[1]);
$note = trim($matches[2]);
$walks = 2;
}
for ($walk = 0;$walk < $walks; $walk++)
{
if ($walk == 1)
{
$isNote = true;
$field = $note;
$columnindex--;
}
// title
if ($field == "title")
{
// headline
if ($config['xls_show_headline'] && $rowindex == 1 && !$isNote)
$worksheet->writeString( 0, $columnindex, $lang['title'], $headlineFormat);
$title = $row['title'];
if ($row['subtitle']) $title .= ' - '.$row['subtitle'];
if ($isNote) $worksheet->writeNote($rowindex, $columnindex++, $lang['title'].":\n".html_entity_decode($title));
else {
if ($row['seen'] == '0' && $config['xls_mark_unseen']) $format = $titleFormatUnseen;
elseif (!empty($row['lentto']) && $config['xls_mark_lent']) $format = $titleFormatLent;
else $format = $titleFormatNormal;
if ($rowindex == 1) $worksheet->setColumn($columnindex, $columnindex, 50);
$imdb = $row['imdbID'];
$link = ($imdb) ? engineGetContentUrl($imdb, engineGetEngine($imdb)) : '';
if($link <> '') $worksheet->writeUrl($rowindex, $columnindex, $link, html_entity_decode($title), $format);
else $worksheet->writeString($rowindex, $columnindex, leftString(html_entity_decode($row['title']),$text_length), $format);
}
$columnindex++;
}
// plot
elseif ($field == "plot")
{
// headline
if ($config['xls_show_headline'] && $rowindex == 1 && !$isNote)
$worksheet->writeString( 0, $columnindex, $lang['plot'], $headlineFormat);
if ($isNote) $worksheet->writeNote($rowindex, $columnindex++, leftString(html_entity_decode($row['plot']),$text_length));
else
{
if (!empty($row['lentto']) && $config['xls_mark_lent']) $format = $plotFormatLent;
else $format = $plotFormatNormal;
if ($rowindex == 1) $worksheet->setColumn($columnindex, $columnindex, 50);
$worksheet->writeString($rowindex, $columnindex++, leftString(html_entity_decode($row['plot']),$text_length), $format);
}
}
// DiskId
elseif ($field == "diskid")
{
// headline
if ($config['xls_show_headline'] && $rowindex == 1 && !$isNote)
$worksheet->writeString( 0, $columnindex, $lang['diskid'], $headlineFormat);
if ($isNote) $worksheet->writeNote($rowindex, $columnindex++, $lang['diskid'].":\n".html_entity_decode($row['diskid']));
else
{
if ($rowindex == 1) $worksheet->setColumn($columnindex, $columnindex, 7);
$worksheet->writeString($rowindex, $columnindex++, html_entity_decode($row['diskid']), $alignCenterFormat);
}
}
// add language
elseif ($field == "language")
{
// headline
if ($config['xls_show_headline'] && $rowindex == 1 && !$isNote)
$worksheet->writeString( 0, $columnindex, $lang['language'], $headlineFormat);
if ($isNote) $worksheet->writeNote($rowindex, $columnindex++, $lang['language'].":\n".html_entity_decode($row['language']));
else
{
if ($rowindex == 1) $worksheet->setColumn($columnindex, $columnindex, 30);
$worksheet->writeString($rowindex, $columnindex++, html_entity_decode($row['language']), $alignLeftFormat);
}
}
// add mediatype
elseif ($field == "mediatype")
{
// headline
if ($config['xls_show_headline'] && $rowindex == 1 && !$isNote)
$worksheet->writeString( 0, $columnindex, $lang['mediatype'], $headlineFormat);
if ($isNote) $worksheet->writeNote($rowindex, $columnindex++, $lang['mediatype'].":\n".html_entity_decode($row['mediatype']));
else
{
if ($rowindex == 1) $worksheet->setColumn($columnindex, $columnindex, 7);
$worksheet->writeString($rowindex, $columnindex++, html_entity_decode($row['mediatype']), $alignLeftFormat);
}
}
// genres
elseif ($field == "genres")
{
// headline
if ($config['xls_show_headline'] && $rowindex == 1 && !$isNote)
$worksheet->writeString( 0, $columnindex, $lang['genres'], $headlineFormat);
if (count($row['genres']))
{
$output_genres = array();
foreach ($row['genres'] as $genre)
{
$output_genres[]= html_entity_decode($genre['name']);
}
if ($isNote) $worksheet->writeNote($rowindex, $columnindex++, $lang['genres'].":\n".join(", ", $output_genres));
else
{
if ($rowindex == 1) $worksheet->setColumn($columnindex, $columnindex, 20);
$worksheet->writeString($rowindex, $columnindex, join(", ", $output_genres), $alignCenterFormat);
}
}
$columnindex++;
}
// runtime
elseif ($field == "runtime")
{
// headline
if ($config['xls_show_headline'] && $rowindex == 1 && !$isNote)
$worksheet->writeString( 0, $columnindex, $lang['runtime'], $headlineFormat);
if ($row['runtime'])
{
if ($isNote) $worksheet->writeNote($rowindex, $columnindex++, $lang['runtime'].":\n".html_entity_decode($row['runtime']).' min');
else
{
if ($rowindex == 1) $worksheet->setColumn($columnindex, $columnindex, 7);
$worksheet->writeString($rowindex, $columnindex, html_entity_decode($row['runtime']).' min', $alignRightFormat);
}
}
$columnindex++;
}
// year
elseif ($field == "year")
{
// headline
if ($config['xls_show_headline'] && $rowindex == 1 && !$isNote)
$worksheet->writeString( 0, $columnindex, $lang['year'], $headlineFormat);
if ($row['year'] != '0000')
{
if ($isNote) $worksheet->writeNote($rowindex, $columnindex++, $lang['year'].":\n".html_entity_decode($row['year']));
else
{
if ($rowindex == 1) $worksheet->setColumn($columnindex, $columnindex, 7);
$worksheet->writeNumber($rowindex, $columnindex, html_entity_decode($row['year']), $alignCenterFormat);
}
}
$columnindex++;
}
// owner
elseif ($field == "owner")
{
// headline
if ($config['xls_show_headline'] && $rowindex == 1 && !$isNote)
$worksheet->writeString( 0, $columnindex, $lang['owner'], $headlineFormat);
if ($isNote) $worksheet->writeNote($rowindex, $columnindex++, $lang['owner'].":\n".html_entity_decode($row['owner']));
else
{
if ($rowindex == 1) $worksheet->setColumn($columnindex, $columnindex, 15);
$worksheet->writeString($rowindex, $columnindex++, html_entity_decode($row['owner']), $alignCenterFormat);
}
}
// lent
elseif ($field == "lent")
{
// headline
if ($config['xls_show_headline'] && $rowindex == 1 && !$isNote)
$worksheet->writeString( 0, $columnindex, $lang['lentto'], $headlineFormat);
if ($isNote) $worksheet->writeNote($rowindex, $columnindex++, $lang['lentto'].":\n".html_entity_decode($row['lentto']));
else
{
if ($rowindex == 1) $worksheet->setColumn($columnindex, $columnindex, 15);
$worksheet->writeString($rowindex, $columnindex++, html_entity_decode($row['lentto']), $alignCenterFormat);
}
}
// seen
elseif ($field == "seen")
{
// headline
if ($config['xls_show_headline'] && $rowindex == 1 && !$isNote)
$worksheet->writeString( 0, $columnindex, $lang['seen'], $headlineFormat);
if ($isNote) {
if ($row['seen'] == 1) $worksheet->writeNote($rowindex, $columnindex++, html_entity_decode($lang['seen']));
else $columnindex++;
}
else
{
if ($rowindex == 1) $worksheet->setColumn($columnindex, $columnindex, 2);
if ($row['seen'] == 1) $worksheet->writeString($rowindex, $columnindex++, "X", $alignCenterFormat); else $columnindex++;
}
}
// insertdate
elseif ($field == "insertdate")
{
// headline
if ($config['xls_show_headline'] && $rowindex == 1 && !$isNote)
$worksheet->writeString( 0, $columnindex, $lang['date'], $headlineFormat);
if ($isNote) $worksheet->writeNote($rowindex, $columnindex++, $lang['date'].":\n".html_entity_decode(preg_replace('/^([0-9]{4}\-[0-9]{2}\-[0-9]{2}).*/','$1',$row['created'])));
else
{
if ($rowindex == 1) $worksheet->setColumn($columnindex, $columnindex, 10);
$worksheet->write($rowindex, $columnindex++, html_entity_decode(preg_replace('/^([0-9]{4}\-[0-9]{2}\-[0-9]{2}).*/','$1',$row['created'])), $alignCenterFormat);
}
}
// custom fields
elseif(preg_match("/^custom[0-4]$/",$field))
{
// headline
if ($config['xls_show_headline'] && $rowindex == 1 && !$isNote)
$worksheet->writeString( 0, $columnindex, $config[$field], $headlineFormat);
//$row[$field] = html_entity_decode($row[$field]);
switch ($config[$field.'type'])
{
case 'ed2k':
if ($isNote) $worksheet->writeNote($rowindex, $columnindex++, $config[$field].":\n".html_entity_decode($row[$field]));
else
{
if ($rowindex == 1) $worksheet->setColumn($columnindex, $columnindex, 12);
$worksheet->writeUrl($rowindex, $columnindex++, html_entity_decode($row[$field]), 'ED2K-Link', $alignCenterFormat);
}
break;
case 'language':
if ($isNote) $worksheet->writeNote($rowindex, $columnindex++, $config[$field].":\n".html_entity_decode($row[$field]));
else
{
if ($rowindex == 1) $worksheet->setColumn($columnindex, $columnindex, 30);
$worksheet->writeString($rowindex, $columnindex++, html_entity_decode($row[$field]), $alignLeftFormat);
}
break;
case 'rating':
if ($row[$field]) $rating = html_entity_decode($row[$field]).'/10'; else $rating = "";
if ($isNote)
{
if ($row[$field]) $worksheet->writeNote($rowindex, $columnindex, $config[$field].":\n".$rating);
$columnindex++;
}
else
{
if ($rowindex == 1) $worksheet->setColumn($columnindex, $columnindex, 7);
if ($row[$field]) $worksheet->writeString($rowindex, $columnindex, $rating,$alignCenterFormat);
$columnindex++;
}
break;
case 'fsk':
if (preg_match("/[0-9]+/",$row[$field]) && !preg_match("/[^0-9]+/",$row[$field]))
{
$fskstr = 'FSK'.html_entity_decode($row[$field]);
}
else $fskstr = html_entity_decode($row[$field]);
if ($isNote) $worksheet->writeNote($rowindex, $columnindex++, $config[$field].":\n".$fskstr);
else
{
if ($rowindex == 1) $worksheet->setColumn($columnindex, $columnindex, 7);
$worksheet->writeString($rowindex, $columnindex++, $fskstr, $alignCenterFormat);
}
break;
case 'barcode':
if ($isNote) $worksheet->writeNote($rowindex, $columnindex++, $config[$field].":\n".html_entity_decode($row[$field]));
else
{
if ($rowindex == 1) $worksheet->setColumn($columnindex, $columnindex, 15);
$worksheet->writeString($rowindex, $columnindex++, html_entity_decode($row[$field]), $alignCenterFormat);
}
break;
case 'orgtitle':
if ($isNote)
{
if (!empty($row[$field])) $worksheet->writeNote($rowindex, $columnindex, $config[$field]. ":\n".html_entity_decode($row[$field]));
$columnindex++;
}
else
{
if ($rowindex == 1) $worksheet->setColumn($columnindex, $columnindex, 50);
$worksheet->writeString($rowindex, $columnindex++, html_entity_decode($row[$field]), $alignLeftFormat);
}
break;
case 'movix':
if ($isNote) $worksheet->writeNote($rowindex, $columnindex++, $config[$field].":\n ".html_entity_decode($row[$field]));
else
{
if ($rowindex == 1) $worksheet->setColumn($columnindex, $columnindex, 7);
$worksheet->writeString($rowindex, $columnindex++, html_entity_decode($row[$field]), $alignCenterFormat);
}
break;
case 'mpaa':
if ($isNote) $worksheet->writeNote($rowindex, $columnindex++, $config[$field].":\n".html_entity_decode($row[$field]), $alignCenterFormat);
else
{
if ($rowindex == 1) $worksheet->setColumn($columnindex, $columnindex, 12);
$worksheet->writeString($rowindex, $columnindex++, html_entity_decode($row[$field]), $alignCenterFormat);
}
break;
case 'bbfc':
if ($isNote) $worksheet->writeNote($rowindex, $columnindex++, $config[$field].":\n".html_entity_decode($row[$field]));
else
{
if ($rowindex == 1) $worksheet->setColumn($columnindex, $columnindex, 7);
$worksheet->writeString($rowindex, $columnindex++, html_entity_decode($row[$field]), $alignCenterFormat);
}
break;
default: // unknown
if ($isNote) $worksheet->writeNote($rowindex, $columnindex++, $config[$field].":\n".html_entity_decode($row[$field]));
else
{
$worksheet->writeString($rowindex, $columnindex++, html_entity_decode($row[$field]), $alignLeftFormat);
}
break;
}
}
} //End of walk
}
$rowindex++;
}
// Let's send the file
$workbook->close();
}
?>

107
videodb/core/xml.core.php Normal file
View File

@@ -0,0 +1,107 @@
<?php
/**
* XML support functions
*
* @package Core
* @author Andreas Götz <cpuidle@gmx.de>
* @version $Id: xml.core.php,v 1.8 2013/04/26 15:09:35 andig2 Exp $
*/
/**
* See http://feedvalidator.org/docs/error/InvalidRFC2822Date.html
*/
$GLOBALS['rss_timestamp_format'] = 'D, j M Y H:i:s O';
/**
* Encodes HTML entities into XML character entities
* this avoids problems with unknown entities in XML
*
* @param string $string HTML string to encode
* @return string encoded string containing XML character entities
*/
function encode_character_entities($string)
{
return strtr($string, get_html_translation_table(HTML_SPECIALCHARS));
# return strtr($string, array_flip(get_html_translation_table(HTML_SPECIALCHARS)));
}
/**
* Create an XML tag
*
* @param string $tag XML tag name
* @param string $value value for XML tag
* @param boolean $encode require encoding of tag value
* @return string XML tag
*/
function createTag($tag, $value, $encode = true)
{
if ($encode) $value = encode_character_entities($value);
return "<$tag>".$value."</$tag>\n";
}
function createContainer($tag, $value = '')
{
return createTag($tag, $value, false);
}
/**
* Convert MySQL Date to RSS timestamp
*
* @return string RFC 2822 Date (http://feedvalidator.org/docs/error/InvalidRFC2822Date.html)
*/
function rss_timestamp($timestamp)
{
global $rss_timestamp_format;
// Lets sort this nasty timestamp nonsense out ;D
$y = substr($timestamp, 0, 4);
$m = substr($timestamp, 5, 2);
$d = substr($timestamp, 8, 2);
$h = substr($timestamp, 11, 2);
$min = substr($timestamp, 14, 2);
$s = substr($timestamp, 17, 2);
$timestamp = mktime($h, $min, $s, $m, $d, $y);
return date($rss_timestamp_format, $timestamp);
}
/**
* Load XML into SimpleXML object
* Fixes potential encoding issue
*/
function load_xml($data)
{
$xml = simplexml_load_string($data, $root = 'SimpleXMLElement', LIBXML_NOCDATA);
// character encoding warning- hack
if ($xml === false)
{
$error = error_get_last();
# dump($error);
// this is nasty- sometimes simplexml_load_string fails but doesn't raise an error
if (preg_match('/simplexml_load_string/i', $error['message']))
{
$xml = simplexml_load_string(utf8_encode($data), $root, LIBXML_NOCDATA);
}
}
return $xml;
}
/**
* Concatenate string-converted xml entities
*/
function xml_join($items, $str = "\n")
{
foreach ($items as $item)
{
if ($data) $data .= $str;
$data .= (string) $item;
}
return $data;
}
?>

186
videodb/core/xml.php Normal file
View File

@@ -0,0 +1,186 @@
<?php
/**
* XML export functions
*
* Lets you browse through your movie collection
*
* @package Core
* @author Andreas Götz <cpuidle@gmx.de>
* @author Kokanovic Branko <branko.kokanovic@gmail.com>
* @version $Id: xml.php,v 1.34 2013/03/10 16:25:35 andig2 Exp $
*/
require_once './core/functions.php';
require_once './core/export.core.php';
require_once './core/xml.core.php';
/**
* Export XML data
*
* @param string $where WHERE clause for SQL statement
*/
function xmlexport($WHERE)
{
global $config;
// get data
$result = exportData($WHERE);
// do adultcheck
// this may not be needed as same check is done in exportData in previous statement
if (is_array($result))
{
$result = array_filter($result, function($video) {return adultcheck($video["id"]);});
}
$xml = '';
// loop over items
foreach ($result as $item)
{
$xml_item = '';
// loop over attributes
foreach ($item as $key => $value)
{
if (!empty($value))
{
if (($key != 'owner_id') && ($key != 'actors') && ($key != 'genres'))
{
$tag = strtolower($key);
$xml_item .= createTag($tag, trim(html_entity_decode_all($value)));
}
}
}
// this is a hack for exporting thumbnail URLs
if ($item['imgurl'] && $config['xml_thumbnails'])
{
$thumb = getThumbnail($item['imgurl']);
if (preg_match('/cache/', $thumb))
$xml_item .= createTag('thumbnail', trim($thumb));
}
// genres
if (count($item['genres']))
{
$xml_genres = '';
foreach ($item['genres'] as $genre)
{
$xml_genres .= createTag('genre', $genre['name']);
}
$xml_item .= createContainer('genres', $xml_genres);
}
// actors
$actors = explode ("\n",$item['actors']);
if (count($actors))
{
$xml_actors = '';
foreach ($actors as $actor)
{
$xml_actor_data = '';
$actor_data = explode("::",$actor);
if (array_key_exists('1', $actor_data))
{
$xml_actor_data .= createTag('name', $actor_data[0]);
}
else
{
$xml_actor_data .= createTag('name', '');
}
if (array_key_exists('1', $actor_data))
{
$xml_actor_data .= createTag('role', $actor_data[1]);
}
else
{
$xml_actor_data .= createTag('role', '');
}
if (array_key_exists('2', $actor_data))
{
$xml_actor_data .= createTag('imdbid', $actor_data[2]);
}
else
{
$xml_actor_data .= createTag('imdbid', '');
}
$xml_actors .= createContainer('actor', $xml_actor_data);
}
$xml_item .= createContainer('actors', $xml_actors);
}
$xml .= createContainer('item', $xml_item);
}
$xml = '<?xml version="1.0" encoding="utf-8"?>'.
"\n".createContainer('catalog', $xml);
// header('Content-type: text/xml');
$mime = (strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE')) ? 'application/force-download' : 'application/octet-stream';
header('Content-type: '.$mime);
header('Content-length: '.strlen($xml));
header('Content-disposition: attachment; filename=videoDB.xml');
echo $xml;
}
/**
* Update RSS File
*
* @author Mike Clark <mike.clark@cinven.com>
*/
function rssexport($WHERE)
{
global $config, $rss_timestamp_format, $filter;
// make sure server doesn't specify something else
header('Content-type: text/xml; charset=utf-8');
if ($filter)
{
$result = exportData($WHERE);
}
else
{
// get the latest items from the DB according to config setting
$SQL = 'SELECT id, title, plot, created
FROM '.TBL_DATA.'
ORDER BY created DESC LIMIT '.$config['shownew'];
$result = runSQL($SQL);
}
// script root
$base = 'http://'.$_SERVER['HTTP_HOST'].dirname($_SERVER['PHP_SELF']);
// setup the RSS Feed
$rssfeed = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
$rssfeed .= '<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">';
$rssfeed .= '<channel>';
$rssfeed .= '<atom:link href="'.$base.'/index.php?export=rss" rel="self" type="application/rss+xml" />';
$rssfeed .= createTag('title', 'VideoDB');
$rssfeed .= createTag('link', $base.'/index.php?export=rss');
$rssfeed .= createTag('description', 'New items posted on VideoDB');
$rssfeed .= createTag('language', 'en-us');
$rssfeed .= createTag('lastBuildDate', date($rss_timestamp_format));
// build the <item></item> section of the Feed
foreach ($result as $item)
{
$xml_item = createTag('title', $item['title']);
$xml_item .= createTag('link', $base.'/show.php?id='.$item['id']);
$xml_item .= createTag('description', $item['plot']);
$xml_item .= createTag('guid', $base.'/show.php?id='.$item['id']);
$xml_item .= createTag('pubDate', rss_timestamp($item['created']));
$rssfeed .= createTag('item', $xml_item, false);
}
$rssfeed .= '</channel>';
$rssfeed .= '</rss>';
header('Content-type: text/xml');
# header('Content-length: '.rssfeed($xml));
# header('Content-disposition: filename=rss.xml');
echo $rssfeed;
}
?>