Browse Source

Merge pull request #7 from Telaxus/master

Merge latest from master
experimental
Janusz Tylek 2 years ago
committed by GitHub
parent
commit
7f6cfbe4c3
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
100 changed files with 2354 additions and 16312 deletions
  1. +0
    -4
      .babelrc
  2. +0
    -10
      .eslintrc.json
  3. +2
    -59
      README.md
  4. +1
    -0
      admin/modules/ConfigInfo.php
  5. +8
    -9
      check.php
  6. +12
    -10
      composer.json
  7. +1664
    -915
      composer.lock
  8. +0
    -1
      console.php
  9. +7
    -7
      console/Develop/CreateModuleCommand.php
  10. +7
    -7
      console/Develop/CreateTestModuleCommand.php
  11. +0
    -32
      console/Modules/RebuildModulesDatabaseCommand.php
  12. +0
    -6
      crowdin.yml
  13. +0
    -0
      dist/.gitkeep
  14. +0
    -12
      folder/nl/en.php.Dutch.old
  15. +0
    -10
      folder/no/en.php.Norwegian.old
  16. +0
    -2127
      folder/ro/en.php.Romanian.old
  17. BIN
      images/epesi_logo_RGB_Solid.png
  18. BIN
      images/epesi_logo_RGB_Solid_login.png
  19. BIN
      images/favicon.png
  20. BIN
      images/logo.png
  21. +0
    -1
      include.php
  22. +1
    -0
      include/config.php
  23. +3
    -3
      include/epesi.php
  24. +2
    -2
      include/error.php
  25. +0
    -15
      include/fontawesome.php
  26. +1
    -1
      include/history.php
  27. +133
    -2
      include/misc.php
  28. +9
    -9
      include/module.php
  29. +1
    -1
      include/module_manager.php
  30. +369
    -273
      include/session.php
  31. +2
    -0
      include/simple_login.php
  32. +130
    -182
      index.php
  33. +2
    -2
      init_js.php
  34. +0
    -5
      libs/bootstrap-datetimepicker.min.css
  35. +0
    -2
      libs/bootstrap-datetimepicker.min.js
  36. BIN
      libs/images/ui-icons_444444_256x240.png
  37. BIN
      libs/images/ui-icons_555555_256x240.png
  38. BIN
      libs/images/ui-icons_777620_256x240.png
  39. BIN
      libs/images/ui-icons_777777_256x240.png
  40. BIN
      libs/images/ui-icons_cc0000_256x240.png
  41. BIN
      libs/images/ui-icons_ffffff_256x240.png
  42. +0
    -117
      libs/jquery.clonePosition.js
  43. +0
    -1216
      libs/moment-with-locales.min.js
  44. +0
    -127
      libs/php-fontawesome.php
  45. +0
    -4
      libs/quickform/.gitignore
  46. +0
    -290
      libs/quickform/Common.php
  47. +0
    -1712
      libs/quickform/QuickForm.php
  48. +0
    -32
      libs/quickform/QuickForm/Error.php
  49. +0
    -490
      libs/quickform/QuickForm/Field/Group/date.php
  50. +0
    -556
      libs/quickform/QuickForm/Field/Group/hierselect.php
  51. +0
    -213
      libs/quickform/QuickForm/Field/Input/advcheckbox.php
  52. +0
    -32
      libs/quickform/QuickForm/Field/Input/autocomplete.php
  53. +0
    -43
      libs/quickform/QuickForm/Field/Input/button.php
  54. +0
    -185
      libs/quickform/QuickForm/Field/Input/checkbox.php
  55. +0
    -272
      libs/quickform/QuickForm/Field/Input/file.php
  56. +0
    -55
      libs/quickform/QuickForm/Field/Input/hidden.php
  57. +0
    -72
      libs/quickform/QuickForm/Field/Input/image.php
  58. +0
    -66
      libs/quickform/QuickForm/Field/Input/password.php
  59. +0
    -171
      libs/quickform/QuickForm/Field/Input/radio.php
  60. +0
    -42
      libs/quickform/QuickForm/Field/Input/reset.php
  61. +0
    -50
      libs/quickform/QuickForm/Field/Input/submit.php
  62. +0
    -55
      libs/quickform/QuickForm/Field/Input/text.php
  63. +0
    -207
      libs/quickform/QuickForm/Field/Multi/automulti.php
  64. +0
    -279
      libs/quickform/QuickForm/Field/Multi/multiselect.php
  65. +0
    -193
      libs/quickform/QuickForm/Field/Select/autoselect.php
  66. +0
    -79
      libs/quickform/QuickForm/Field/Select/hiddenselect.php
  67. +0
    -39
      libs/quickform/QuickForm/Field/Static/header.php
  68. +0
    -42
      libs/quickform/QuickForm/Field/Static/html.php
  69. +0
    -97
      libs/quickform/QuickForm/Field/Static/link.php
  70. +0
    -474
      libs/quickform/QuickForm/Field/group.php
  71. +0
    -101
      libs/quickform/QuickForm/Field/input.php
  72. +0
    -144
      libs/quickform/QuickForm/Field/multi.php
  73. +0
    -438
      libs/quickform/QuickForm/Field/select.php
  74. +0
    -114
      libs/quickform/QuickForm/Field/static.php
  75. +0
    -120
      libs/quickform/QuickForm/Field/textarea.php
  76. +0
    -13
      libs/quickform/QuickForm/Field/toHtml.php
  77. +0
    -108
      libs/quickform/QuickForm/Field/xbutton.php
  78. +0
    -84
      libs/quickform/QuickForm/Renderer.php
  79. +0
    -321
      libs/quickform/QuickForm/Renderer/Array.php
  80. +0
    -367
      libs/quickform/QuickForm/Renderer/ArraySmarty.php
  81. +0
    -416
      libs/quickform/QuickForm/Renderer/Default.php
  82. +0
    -159
      libs/quickform/QuickForm/Renderer/QuickHtml.php
  83. +0
    -417
      libs/quickform/QuickForm/Renderer/TCMSArray.php
  84. +0
    -401
      libs/quickform/QuickForm/Renderer/TCMSArraySmarty.php
  85. +0
    -43
      libs/quickform/QuickForm/Renderer/TCMSDefault.js
  86. +0
    -515
      libs/quickform/QuickForm/Renderer/TCMSDefault.php
  87. +0
    -58
      libs/quickform/QuickForm/Rule.php
  88. +0
    -99
      libs/quickform/QuickForm/Rule/Callback.php
  89. +0
    -82
      libs/quickform/QuickForm/Rule/Compare.php
  90. +0
    -93
      libs/quickform/QuickForm/Rule/CompareString.php
  91. +0
    -49
      libs/quickform/QuickForm/Rule/Email.php
  92. +0
    -47
      libs/quickform/QuickForm/Rule/Range.php
  93. +0
    -80
      libs/quickform/QuickForm/Rule/Regex.php
  94. +0
    -39
      libs/quickform/QuickForm/Rule/Required.php
  95. +0
    -324
      libs/quickform/QuickForm/RuleRegistry.php
  96. +0
    -398
      libs/quickform/QuickForm/element.php
  97. +0
    -42
      libs/quickform/autocomplete_update.php
  98. +0
    -155
      libs/quickform/docs/elements.php
  99. +0
    -64
      libs/quickform/docs/filters.php
  100. +0
    -104
      libs/quickform/docs/formrule.php

+ 0
- 4
.babelrc View File

@@ -1,4 +0,0 @@
{
"presets": ["env"],
"plugins": ["transform-runtime", "transform-function-bind", "transform-class-properties"]
}

+ 0
- 10
.eslintrc.json View File

@@ -1,10 +0,0 @@
{
"extends": "airbnb-base",
"parser": "babel-eslint",
"env": {
"browser": true
},
"globals": {
"jQuery": true
}
}

+ 2
- 59
README.md View File

@@ -4,66 +4,9 @@

<b>EPESI BIM</b> (Business Information Manager) is a fully functional web CRM/ERP application to store, organize, access and share business records. Manage your data precisely, flexibly and easily, simplifying internal communication and making work-flow more efficient.

<b>About</b>
<b>Attention</b>

EPESI BIM is a result of many years of experience working with SMB businesses and addresses inefficiencies of current e-mail “collaboration” workflow and commonplace data management using inadequate spreadsheet applications. It is a completely web based application designed for small and medium-sized enterprises trying to optimize business processes, simplify office work and reduce administrative costs. It does not require any client to be installed - any modern browser on any operating system will work - drastically reducing the deployment cost.

Our software can make your organization more efficient, better organized and more competitive. We can help you simplify and automate internal procedures with management of important business information.

- To eliminate e-mail in our workplace we internally use <b>EPESI</b> for all tasks, notes, projects and tickets - making our life more organized.
- In addition we use great multiplatform and programmable chat: <b>Telegram https://telegram.org/</b> available here at Github as well: https://github.com/telegramdesktop

Telegram is a messaging app with a focus on speed and security, it’s super-fast, simple and free. You can use Telegram on all your devices at the same time — your messages sync seamlessly across any number of your phones, tablets or computers.

- Epesi is already integrated with Telegram messaging platform te receive notifications from the <b>Watchdog</b> module (free and included with the latest release) as well as with Time tracking and reporting module integrated with Premium module Timesheets http://epe.si/modules/premium/timesheets/

More information on epesi - description of functionality, demos and more visit: http://epe.si/free-crm/

<b>Support</b>
- For users - please visit our forum http://forum.epesibim.com/ - to receive free technical assistance
- For developers - please open issues here: https://github.com/Telaxus/EPESI/issues
- For Premium Support - paid service provided by Telaxus LLC - visit: http://telaxus.com/premium-support/

<b>Setup:</b>
- Online demo: http://demo.epesibim.com/
- Automatic - no technical expertise needed - setup hosting at epesi Cloud (free 30-day trial): http://epe.si/hosting
- Autoinstall via cPanel using Softaculous: https://www.softaculous.com/apps/erp/EPESI
</br>
Video tutorial on how to install epesi using Softaculous autoinstaller via cPanel - https://www.youtube.com/watch?v=FR4mQsHUNCY

<b>DIY - Do It Yourself manual methods:</b>
For experienced users and server administrators:
It requires properly configured HTTP server with PHP and MySQL or PostgreSQL database server - so called LAMP stack: https://en.wikipedia.org/wiki/LAMP_(software_bundle)

- Download from Sourceforge: http://sourceforge.net/projects/epesi
- Use Easy Install Script: http://sourceforge.net/projects/epesi/files/easy%20installer/
- Github: https://github.com/Telaxus/epesi

<b>Reviews</b>
- Users reviews collected from our support forum: http://epe.si/reviews/
- Sourceforge: https://sourceforge.net/projects/epesi/reviews/
- Review from September 19, 2016: "Top 10 Open Source CRM" by http://www.datamation.com/open-source/top-10-open-source-crm.html

<b>License:</b>

EPESI is released under the MIT License

Copyright © 2006-2016 Telaxus LLC

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/orsell 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.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHERDEALINGS IN THE SOFTWARE.

<b>Credits:</b>

Telaxus LLC http://telaxus.com/

- Telaxus LLC is a technology company specializing in developoment of CRM and ERP solutions for small and medium size businesses utilizing our own platform - EPESI Business Information Manager.


<i>Copyright © 2006-2016 Telaxus LLC</i>
This project is no longer maintained. Visit https://github.com/jtylek/Epesi for up to date version.

Enjoy,
<b>EPESI Team</b>

+ 1
- 0
admin/modules/ConfigInfo.php View File

@@ -78,6 +78,7 @@ class ConfigInfo extends AdminModule {
$this->printTD('Set Session: ', (SET_SESSION ? 'YES' : 'NO'));

$this->printTD('Read Only Session: ', (READ_ONLY_SESSION ? 'YES' : 'NO'));
$this->printTD('Mobile Device: ', (MOBILE_DEVICE ? 'YES' : 'NO'));
$this->printTD('First Run: ', (FIRST_RUN ? 'YES' : 'NO'));
$this->printTD('Hosting Mode: ', (HOSTING_MODE ? 'YES' : 'NO'));
$this->printTD('Trial Mode: ', (TRIAL_MODE ? 'YES' : 'NO'));


+ 8
- 9
check.php View File

@@ -210,11 +210,11 @@ foreach ($checks as $c) {
$solution = false;
foreach ($c['tests'] as $t) {
switch ($t['severity']) {
case 0: $class = 'text-success'; break;
case 1: $class = 'text-warning'; $solution = true; break;
case 2: $class = 'text-danger'; $solution = true; break;
case 0: $color = '#00CC00'; break;
case 1: $color = '#CCAA00'; $solution = true; break;
case 2: $color = 'red'; $solution = true; break;
}
$html .= '<span style="font-weight:bold;float:right;" class="'.$class.'">'.$t['status'].'</span>';
$html .= '<span style="font-weight:bold;float:right;margin-right:100px;color:'.$color.'">'.$t['status'].'</span>';
$html .= '<span style="margin-left:40px;">'.$t['label'].'</span>';
$html .= '<br>';
}
@@ -228,12 +228,11 @@ foreach ($checks as $c) {
$html .= '<br><br>';
$html .= '<font size=-2>';
$html .= 'Legend:<br>';
$html .= '<div><span class="text-success">Green</span> - matches EPESI requirements</div>';
$html .= '<div><span class="text-warning">Yellow</span> - shouldn\'t prevent EPESI from running, but it\'s recommended to change the settings</div>';
$html .= '<div><span class="text-danger">Red</span> - check failed, it\'s necessary to change the settings</div>';
$html .= '<span style="color:#00CC00;">Green</span> - matches EPESI requirements<br>';
$html .= '<span style="color:#CCAA00;">Yellow</span> - shouldn\'t prevent EPESI from running, but it\'s recommended to change the settings<br>';
$html .= '<span style="color:red;">Red</span> - check failed, it\'s necessary to change the settings<br>';
$html .= '</font>';

print('<div class="col-md-6 col-md-offset-3"><div class="panel panel-default"><div class="panel-body">');
if ($fullscreen) {
if (class_exists('Utils_FrontPageCommon'))
Utils_FrontPageCommon::display('EPESI Compatibility check', $html);
@@ -242,5 +241,5 @@ if ($fullscreen) {
} else {
print($html);
}
print('</div></div></div>');
?>

+ 12
- 10
composer.json View File

@@ -8,20 +8,23 @@
"fzaninotto/faker": "^1.6",
"phpFastCache/phpFastCache": "^5.0",
"ifsnop/mysqldump-php": "dev-master",
"memio/memio": "^1.0",
"psy/psysh": "@stable",
"anahkiasen/underscore-php": "^2.0",
"moneyphp/money": "^3.0",
"enyo/dropzone": "@stable",
"ezyang/htmlpurifier": "^4.9",
"moneyphp/money": "^3.0"
"moneyphp/money": "^3.0",
"tecnickcom/tcpdf": "^6.2",
"memio/memio": "^2.0"
},
"scripts": {
"post-install-cmd": [
"@composer -d=\"modules/CRM/Mail\" install",
"@composer -d=\"modules/Libs/PHPExcel\" install",
"@composer -d=\"modules/Libs/TCPDF\" install"
]
"@composer -d\"modules/CRM/Mail\" install",
"@composer -d\"modules/Libs/PHPExcel\" install",
"@composer -d\"vendor/tecnickcom/tcpdf\" install",
"@composer -d\"vendor/tecnickcom/tcpdf\" dump-autoload"
],
"post-update-cmd": [
"@composer -d\"vendor/tecnickcom/tcpdf\" dump-autoload"
]
},
"autoload": {
"psr-4": {
@@ -30,8 +33,7 @@
},
"psr-0": {
"": "modules/"
},
"classmap": ["libs/quickform"]
}
},
"require-dev": {
"codeception/codeception": "*",


+ 1664
- 915
composer.lock
File diff suppressed because it is too large
View File


+ 0
- 1
console.php View File

@@ -27,7 +27,6 @@ $application->add(new \Epesi\Console\Modules\EnableModuleCommand());
$application->add(new \Epesi\Console\Modules\InstallModuleCommand());
$application->add(new \Epesi\Console\Modules\UninstallModuleCommand());
$application->add(new \Epesi\Console\Modules\EnableAllModuleCommand());
$application->add(new \Epesi\Console\Modules\RebuildModulesDatabaseCommand());
$application->add(new \Epesi\Console\CacheRebuildCommand());
$application->add(new \Epesi\Console\ThemeRebuildCommand());
$application->add(new \Epesi\Console\Maintenance\MaintenanceStatusCommand());


+ 7
- 7
console/Develop/CreateModuleCommand.php View File

@@ -10,7 +10,7 @@ use Symfony\Component\Console\Output\OutputInterface;

use Memio\Memio\Config\Build;
use Memio\Model\File;
use Memio\Model\Object;
use Memio\Model\Objekt;
use Memio\Model\Method;
use Memio\Model\Argument;

@@ -74,9 +74,9 @@ class CreateModuleCommand extends Command
$file_main = $module_dir . '/' . $core_name . '_0.php';
$myFile = File::make($file_main)
->setStructure(
Object::make($module_type)
Objekt::make($module_type)
->extend(
Object::make('Module'))
Objekt::make('Module'))
->addMethod(
Method::make('body')
)
@@ -91,9 +91,9 @@ class CreateModuleCommand extends Command
$file_common = $module_dir . '/' . $core_name . 'Common_0.php';
$myFile = File::make($file_common)
->setStructure(
Object::make($module_type . 'Common')
Objekt::make($module_type . 'Common')
->extend(
Object::make('ModuleCommon')
Objekt::make('ModuleCommon')
)
);

@@ -112,9 +112,9 @@ class CreateModuleCommand extends Command
$file_install = $module_dir . '/' . $core_name . 'Install.php';
$myFile = File::make($file_install)
->setStructure(
Object::make($module_type . 'Install')
Objekt::make($module_type . 'Install')
->extend(
Object::make('ModuleInstall'))
Objekt::make('ModuleInstall'))
->addMethod(
Method::make('install')
->setBody("{$t}{$t}return true;"))


+ 7
- 7
console/Develop/CreateTestModuleCommand.php View File

@@ -10,7 +10,7 @@ use Symfony\Component\Console\Output\OutputInterface;

use Memio\Memio\Config\Build;
use Memio\Model\File;
use Memio\Model\Object;
use Memio\Model\Objekt;
use Memio\Model\Method;
use Memio\Model\Argument;

@@ -66,9 +66,9 @@ class CreateTestModuleCommand extends Command
$file_main = $module_dir . '/' . $module_name . '_0.php';
$myFile = File::make($file_main)
->setStructure(
Object::make($module_type)
Objekt::make($module_type)
->extend(
Object::make('Module'))
Objekt::make('Module'))
->addMethod(
Method::make('body')
)
@@ -84,9 +84,9 @@ class CreateTestModuleCommand extends Command
$file_common = $module_dir . '/' . $module_name . 'Common_0.php';
$myFile = File::make($file_common)
->setStructure(
Object::make($module_type . 'Common')
Objekt::make($module_type . 'Common')
->extend(
Object::make('ModuleCommon')
Objekt::make('ModuleCommon')
)
->addMethod(
Method::make('menu')
@@ -108,9 +108,9 @@ class CreateTestModuleCommand extends Command
$file_install = $module_dir . '/' . $module_name . 'Install.php';
$myFile = File::make($file_install)
->setStructure(
Object::make($module_type . 'Install')
Objekt::make($module_type . 'Install')
->extend(
Object::make('ModuleInstall'))
Objekt::make('ModuleInstall'))
->addMethod(
Method::make('install')
->setBody("{$t}{$t}return true;"))


+ 0
- 32
console/Modules/RebuildModulesDatabaseCommand.php View File

@@ -1,32 +0,0 @@
<?php

namespace Epesi\Console\Modules;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

class RebuildModulesDatabaseCommand extends Command
{
protected function configure()
{
$this
->setName('module:rebuild')
->setDescription('Rebuild modules database')
;
}

protected function execute(InputInterface $input, OutputInterface $output)
{
$modules = \Base_SetupCommon::refresh_available_modules();

$table = new Table($output);
$table->setHeaders(array('<fg=white;options=bold>Name</fg=white;options=bold>', '<fg=white;options=bold>Version</fg=white;options=bold>'));
foreach ($modules as $name => $module) {
$table->addRow(array($name, $module[0]));
}

$table->render();
}
}

+ 0
- 6
crowdin.yml View File

@@ -1,6 +0,0 @@
files:
- source: '*/en.php'
translation: /folder/%two_letters_code%/%original_file_name%.%language%.old
languages_mapping:
two_letters_code:
en: .php

+ 0
- 0
dist/.gitkeep View File


+ 0
- 12
folder/nl/en.php.Dutch.old View File

@@ -1,12 +0,0 @@
<?php
/**
* Translation file.
* @package epesi-translations
* @subpackage en
*/
global $translations;
$translations['Projects']='';
$translations['Due Date']='';
$translations['Project Name']='';
$translations['Bugtrack']='';
$translations['Bug (attachment) #%d, %s']='';

+ 0
- 10
folder/no/en.php.Norwegian.old View File

@@ -1,10 +0,0 @@
<?php
/**
* Translation file.
* @package epesi-translations
* @subpackage en
*/
global $translations;
$translations['This text can be translated.']='';
$translations['Here you can have some numbers: %d, %d, %d but you can still translate whole text.']='';
$translations['Hello world!']='';

+ 0
- 2127
folder/ro/en.php.Romanian.old
File diff suppressed because it is too large
View File


BIN
images/epesi_logo_RGB_Solid.png View File

Before After
Width: 300  |  Height: 64  |  Size: 21 KiB

BIN
images/epesi_logo_RGB_Solid_login.png View File

Before After
Width: 600  |  Height: 128  |  Size: 31 KiB

BIN
images/favicon.png View File

Before After
Width: 16  |  Height: 16  |  Size: 1.4 KiB Width: 16  |  Height: 16  |  Size: 951 B

BIN
images/logo.png View File

Before After
Width: 550  |  Height: 200  |  Size: 45 KiB Width: 250  |  Height: 50  |  Size: 6.1 KiB

+ 0
- 1
include.php View File

@@ -37,7 +37,6 @@ try {
require_once('include/history.php');
require_once('include/patches.php');
require_once('include/simple_login.php');
require_once('include/fontawesome.php');
} catch (Exception $e) {
die($e->getMessage());
}

+ 1
- 0
include/config.php View File

@@ -45,6 +45,7 @@ if(!defined('TRACKING_CODE')) define('TRACKING_CODE','');
if(!defined('JS_OUTPUT')) define('JS_OUTPUT',0);
if(!defined('SET_SESSION')) define('SET_SESSION',1);
if(!defined('READ_ONLY_SESSION')) define('READ_ONLY_SESSION',0);
if(!defined('MOBILE_DEVICE')) define('MOBILE_DEVICE',0);
if(!defined('DIRECTION_RTL')) define('DIRECTION_RTL',0);

if(!defined('FIRST_RUN')) define('FIRST_RUN','FirstRun');


+ 3
- 3
include/epesi.php View File

@@ -326,8 +326,8 @@ class Epesi {
foreach($to_cleanup as $k) {
$mod = ModuleManager::get_instance($k);
if($mod === null) {
$xx = explode('__',$k);
$yy = explode('--',$xx[count($xx)-1]);
$xx = explode('/',$k);
$yy = explode('|',$xx[count($xx)-1]);
$mod = $yy[0];
if(is_callable(array($mod.'Common','destroy')))
call_user_func(array($mod.'Common','destroy'),$k,isset($_SESSION['client']['__module_vars__'][$k])?$_SESSION['client']['__module_vars__'][$k]:null);
@@ -434,7 +434,7 @@ class Epesi {
}
if(!isset($_SESSION['client']['custom_debug']) || $debug!=$_SESSION['client']['custom_debug']) {
self::text($debug,'debug');
if ($debug) Epesi::js("jq('#debug_content').show();");
if ($debug) Epesi::js("$('debug_content').style.display='block';");
$_SESSION['client']['custom_debug'] = $debug;
}



+ 2
- 2
include/error.php View File

@@ -27,8 +27,8 @@ class ErrorHandler {
chdir(dirname(dirname(__FILE__)));
Epesi::clean();
if(DISPLAY_ERRORS) {
Epesi::js("jq('#debug_content').show();");
Epesi::text('<pre>'.$buffer.'</pre><hr>','error_box','prepend');
Epesi::js("$('debug_content').style.display='block';");
Epesi::text('<pre>' . $buffer . '</pre><hr>','error_box','prepend');
}
Epesi::alert('There was an error in one of epesi modules.'.((DISPLAY_ERRORS)?' Details are displayed at the bottom of the page, please send this information to system administrator.':''));
return Epesi::get_output();


+ 0
- 15
include/fontawesome.php View File

@@ -1,15 +0,0 @@
<?php
/**
* @author Paul Bukowski <pbukowski@telaxus.com>
* @version 1.0
* @copyright Copyright &copy; 2017, Telaxus LLC
* @license SPL
* @package epesi-base
*/
defined("_VALID_ACCESS") || die('Direct access forbidden');
require_once(EPESI_LOCAL_DIR.'/libs/php-fontawesome.php');
class FontAwesome extends Smk_FontAwesome {
public static function get($class_prefix = 'fa-'){
return parent::getArray(EPESI_LOCAL_DIR.'/node_modules/font-awesome/css/font-awesome.css',$class_prefix);
}
}

+ 1
- 1
include/history.php View File

@@ -17,7 +17,7 @@ class History {

private static function session_id()
{
return DBSession::truncated_session_id();
return EpesiSession::truncated_id();
}
public static function back() {


+ 133
- 2
include/misc.php View File

@@ -316,7 +316,7 @@ function recalculate_time($date,$time) {
function escapeJS($str,$double=true,$single=true) {return Epesi::escapeJS($str,$double,$single);}

function get_epesi_url() {
if(defined('EPESI_URL')) return rtrim(EPESI_URL,'/');
if(defined('EPESI_URL')) return rtrim(EPESI_URL,'/') . '/';
if(php_sapi_name() == 'cli')
return dirname(dirname(__FILE__));
$protocol = (isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS'])!== "off") ? 'https://' : 'http://';
@@ -327,7 +327,7 @@ function get_epesi_url() {
$domain_name = $_SERVER['SERVER_NAME'];
}
$url = ($domain_name ? ($protocol . $domain_name) : '') . EPESI_DIR;
return trim($url);
return rtrim(trim($url), '/') . '/';
}

function get_client_ip_address()
@@ -386,6 +386,137 @@ function create_html_form(& $form_name, $action_url, $variables, $target = null,
return $html;
}

////////////////////////////////////////////////////
// mobile devices

function detect_mobile_device(){
// check if the user agent value claims to be windows but not windows mobile
if(stristr($_SERVER['HTTP_USER_AGENT'],'windows')&&!(stristr($_SERVER['HTTP_USER_AGENT'],'windows ce')||stristr($_SERVER['HTTP_USER_AGENT'],'windows mobile')||stristr($_SERVER['HTTP_USER_AGENT'],'palm'))){
return false;
}
// check if the user agent gives away any tell tale signs it's a mobile browser
if(preg_match('/up.browser|up.link|windows ce|iemobile|mini|mmp|symbian|midp|wap|phone|pocket|mobile|pda|psp|ppc|symbian/i',$_SERVER['HTTP_USER_AGENT'])){
return true;
}
// check the http accept header to see if wap.wml or wap.xhtml support is claimed
if(isset($_SERVER['HTTP_ACCEPT']) && (stristr($_SERVER['HTTP_ACCEPT'],'text/vnd.wap.wml')||stristr($_SERVER['HTTP_ACCEPT'],'application/vnd.wap.xhtml+xml'))){
return true;
}
// check if there are any tell tales signs it's a mobile device from the _server headers
if(isset($_SERVER['HTTP_X_WAP_PROFILE'])||isset($_SERVER['HTTP_PROFILE'])||isset($_SERVER['X-OperaMini-Features'])||isset($_SERVER['UA-pixels'])){
return true;
}
// build an array with the first four characters from the most common mobile user agents
$a = array(
'acs-'=>'acs-',
'alav'=>'alav',
'alca'=>'alca',
'amoi'=>'amoi',
'audi'=>'audi',
'aste'=>'aste',
'avan'=>'avan',
'benq'=>'benq',
'bird'=>'bird',
'blac'=>'blac',
'blaz'=>'blaz',
'brew'=>'brew',
'cell'=>'cell',
'cldc'=>'cldc',
'cmd-'=>'cmd-',
'dang'=>'dang',
'doco'=>'doco',
'eric'=>'eric',
'hipt'=>'hipt',
'inno'=>'inno',
'ipaq'=>'ipaq',
'java'=>'java',
'jigs'=>'jigs',
'kddi'=>'kddi',
'keji'=>'keji',
'leno'=>'leno',
'lg-c'=>'lg-c',
'lg-d'=>'lg-d',
'lg-g'=>'lg-g',
'lge-'=>'lge-',
'maui'=>'maui',
'maxo'=>'maxo',
'midp'=>'midp',
'mits'=>'mits',
'mmef'=>'mmef',
'mobi'=>'mobi',
'mot-'=>'mot-',
'moto'=>'moto',
'mwbp'=>'mwbp',
'nec-'=>'nec-',
'newt'=>'newt',
'noki'=>'noki',
'opwv'=>'opwv',
'palm'=>'palm',
'pana'=>'pana',
'pant'=>'pant',
'pdxg'=>'pdxg',
'phil'=>'phil',
'play'=>'play',
'pluc'=>'pluc',
'port'=>'port',
'prox'=>'prox',
'qtek'=>'qtek',
'qwap'=>'qwap',
'sage'=>'sage',
'sams'=>'sams',
'sany'=>'sany',
'sch-'=>'sch-',
'sec-'=>'sec-',
'send'=>'send',
'seri'=>'seri',
'sgh-'=>'sgh-',
'shar'=>'shar',
'sie-'=>'sie-',
'siem'=>'siem',
'smal'=>'smal',
'smar'=>'smar',
'sony'=>'sony',
'sph-'=>'sph-',
'symb'=>'symb',
't-mo'=>'t-mo',
'teli'=>'teli',
'tim-'=>'tim-',
'tosh'=>'tosh',
'treo'=>'treo',
'tsm-'=>'tsm-',
'upg1'=>'upg1',
'upsi'=>'upsi',
'vk-v'=>'vk-v',
'voda'=>'voda',
'wap-'=>'wap-',
'wapa'=>'wapa',
'wapi'=>'wapi',
'wapp'=>'wapp',
'wapr'=>'wapr',
'webc'=>'webc',
'winw'=>'winw',
'winw'=>'winw',
'xda-'=>'xda-'
);
// check if the first four characters of the current user agent are set as a key in the array
if(isset($a[substr($_SERVER['HTTP_USER_AGENT'],0,4)])){
return true;
}
}

function detect_iphone(){
if (!isset($_SERVER['HTTP_USER_AGENT'])) return false;
if(preg_match('/iphone/i',$_SERVER['HTTP_USER_AGENT'])||preg_match('/iPad/i',$_SERVER['HTTP_USER_AGENT'])||preg_match('/ipod/i',$_SERVER['HTTP_USER_AGENT'])||preg_match('/android/i',$_SERVER['HTTP_USER_AGENT'])||preg_match('/webOS/i',$_SERVER['HTTP_USER_AGENT'])){
return true;
}
return false;
}

if(detect_iphone())
define('IPHONE',1);
else
define('IPHONE',0);

////////////////////////////
// strip epesi invalid html code


+ 9
- 9
include/module.php View File

@@ -139,7 +139,7 @@ abstract class Module extends ModulePrimitive {
$this->children[$type] = array();
$this->children[$type][$instance] = & $ch;
if(DEBUG)
Epesi::debug('registering '.$this->get_path().'--'.$ch->get_node_id());
Epesi::debug('registering '.$this->get_path().'/'.$ch->get_node_id());
}

private final function get_new_child_instance_id($type) {
@@ -157,7 +157,7 @@ abstract class Module extends ModulePrimitive {
$x = false;
return $x;
}
$yy = explode('__',$id);
$yy = explode('|',$id);
return $this->children[$yy[0]][$yy[1]];
}

@@ -184,7 +184,7 @@ abstract class Module extends ModulePrimitive {
if($this->clear_child_vars) return;
$module_type = str_replace('/','_',$module_type);
if(!isset($name)) $name = $this->get_new_child_instance_id($module_type);
$this->frozen_modules[$module_type.'__'.$name] = 1;
$this->frozen_modules[$module_type.'|'.$name] = 1;
}

//endregion
@@ -840,7 +840,7 @@ abstract class Module extends ModulePrimitive {
* @param string $function_name function to call (get output from), if user has enought privileges.
* @return mixed if access denied returns false, else true
*/
public final function display_module(& $m, $args=null, $function_name = null, $template = null) {
public final function display_module(& $m, $args=null, $function_name = null) {
$ret = $this->get_html_of_module($m,$args,$function_name);
if($ret===false) return false;
print($ret);
@@ -873,7 +873,7 @@ abstract class Module extends ModulePrimitive {

if (!$m->check_access($function_name))
return false;
//we cannot trigger error here, because logout doesn't work
//we cannot trigger error here, couse logout doesn't work
//trigger_error('Method given as argument 2 for display_module inaccessible.<br>$'.$this->get_type().'->display_module(\''.$m->get_type().'\','.$args.',\''.$function_name.'\');',E_USER_ERROR);

$s = & $m->get_module_variable('__shared_unique_vars__',array());
@@ -887,7 +887,7 @@ abstract class Module extends ModulePrimitive {
$path = $m->get_path();
if($this->is_inline_display()) $m->set_inline_display();
if(!$m->is_inline_display()) {
Epesi::$content[$path]['span'] = $this_path.'__'.$this->children_count_display.'content';
Epesi::$content[$path]['span'] = $this_path.'|'.$this->children_count_display.'content';
$this->children_count_display++;
}
Epesi::$content[$path]['module'] = & $m;
@@ -1073,7 +1073,7 @@ abstract class Module extends ModulePrimitive {
*/
public final function get_node_id()
{
return $this->type_with_submodule . '__' . $this->instance;
return $this->type_with_submodule . '|' . $this->instance;
}

/**
@@ -1084,13 +1084,13 @@ abstract class Module extends ModulePrimitive {
*
* Example:
* Module named Base/Box, instance 1, without parents:
* get_path returns '--Base_Box-1'
* get_path returns '/Base_Box|1'
*
* @return string unique module name
*/
public final function get_path() {
if(!isset($this->path))
$this->path = $this->get_parent_path().'--'.$this->get_node_id();
$this->path = $this->get_parent_path().'/'.$this->get_node_id();
return $this->path;
}



+ 1
- 1
include/module_manager.php View File

@@ -755,7 +755,7 @@ class ModuleManager {
* @return bool null if module instance was not found, requested module object otherwise
*/
public static final function get_instance($path) {
$xx = explode('--',$path);
$xx = explode('/',$path);
$curr = self::$root;
if(is_object($curr) && $curr->get_node_id() != $xx[1]) {
$x = null;


+ 369
- 273
include/session.php View File

@@ -8,324 +8,426 @@
*/
defined("_VALID_ACCESS") || die('Direct access forbidden');


require_once('database.php');

class DBSession {
class EpesiSession implements SessionHandlerInterface{
const MAX_SESSION_ID_LENGTH = 128;
private static $lifetime;
private static $memcached;
private static $memcached_lock_time;
private static $session_fp;
private static $session_client_fp;
private static $session_type;
/**
* @var EpesiSessionStorage
*/
private static $storage;
private static $storageMap = [
'file' => EpesiSessionFileStorage::class,
'memcache' => EpesiSessionMemcachedStorage::class,
'memcached' => EpesiSessionMemcachedStorage::class,
'sql' => EpesiSessionDBStorage::class,
];

public static function truncated_session_id($session_id = null)
public static function truncated_id($session_id = null)
{
if ($session_id === null) {
$session_id = session_id();
}
return substr($session_id, 0, self::MAX_SESSION_ID_LENGTH);
return substr($session_id?: session_id(), 0, self::MAX_SESSION_ID_LENGTH);
}
public static function create()
{
return new static();
}
public static function get($name)
{
return self::storage()->read($name);
}
public static function set($name, $data)
{
return self::storage()->write($name, $data);
}
public static function destroy_client($name, $i) {
$name = self::truncated_id($name);
self::storage()->destroy($name . '_' . $i);
DB::Execute('DELETE FROM history WHERE session_name=%s AND client_id=%d',array($name,$i));
}

public static function open($path, $name) {
self::$lifetime = min(ini_get("session.gc_maxlifetime"),2592000-1); //less then 30 days
switch(SESSION_TYPE) {
case 'file':
case 'sql':
self::$session_type = SESSION_TYPE;
break;
case 'memcache':
if(MEMCACHE_SESSION_SERVER) {
$srv = explode(':',MEMCACHE_SESSION_SERVER,2);
self::$memcached = new EpesiMemcache();
if(!self::$memcached->addServer($srv[0],(isset($srv[1])?$srv[1]:11211)))
trigger_error('Cannot connect to memcache server',E_USER_ERROR);
}
if(self::$memcached) self::$session_type = SESSION_TYPE;
else self::$session_type = 'file';
break;
default:
self::$session_type = 'file';
}
if(self::$session_type=='memcache') {
self::$memcached_lock_time = ini_get("max_execution_time");
if(!self::$memcached_lock_time) self::$memcached_lock_time = 60;
self::$memcached_lock_time += time();
}
public function open($path, $name) {
self::storage();
return true;
}

public static function close() {
//self::gc(self::$lifetime);
/**
* @return EpesiSessionStorage
*/
public static function storage() {
$lifetime = min(ini_get('session.gc_maxlifetime'),2592000-1); //less then 30 days
self::$storage = self::$storage?: EpesiSessionStorage::factory(self::getStorageClass(), $lifetime);
return self::$storage;
}
public static function getStorageClass() {
$defaultClass = reset(self::$storageMap);
$class = self::$storageMap[SESSION_TYPE]?? $defaultClass;
return $class::active()? $class: $defaultClass;
}
public function close() {
return true;
}

public static function read($name) {
$name = self::truncated_session_id($name);
public function read($name) {
$name = self::truncated_id($name);
//main session
switch(self::$session_type) {
case 'file':
if(!file_exists(FILE_SESSION_DIR)) mkdir(FILE_SESSION_DIR);
$sess_file = rtrim(FILE_SESSION_DIR,'\\/').'/'.FILE_SESSION_TOKEN.$name;
if(!file_exists($sess_file)) file_put_contents($sess_file,'');
self::$session_fp = fopen($sess_file,'r+');
if(!READ_ONLY_SESSION && !flock(self::$session_fp,LOCK_EX))
trigger_error('Unable to get lock on session file='.$sess_file,E_USER_ERROR);
$ret = stream_get_contents(self::$session_fp);
break;
case 'memcache':
if(!READ_ONLY_SESSION && !self::$memcached->lock(MEMCACHE_SESSION_TOKEN.$name,self::$memcached_lock_time))
trigger_error('Unable to get lock on session mem='.$name,E_USER_ERROR);
$ret = '';
for($i=0;; $i++) {
$rr = self::$memcached->get(MEMCACHE_SESSION_TOKEN.$name.'/'.$i);
if($rr==='' || $rr===false || $rr===null) break;
$ret .= $rr;
}
break;
case 'sql':
$ret = DB::GetCol('SELECT data FROM session WHERE name = %s AND expires > %d'.(READ_ONLY_SESSION?'':' FOR UPDATE'), array($name, time()-self::$lifetime));
if($ret) $ret = $ret[0];
break;
}
if($ret) $_SESSION = unserialize($ret);

if(CID!==false) {
if(!is_numeric(CID))
trigger_error('Invalid client id.',E_USER_ERROR);
// ----- main session -----
if ($mainData = self::storage()->read($name))
$_SESSION = $mainData;
if (CID===false) return '';
if(!is_numeric(CID))
trigger_error('Invalid client id.',E_USER_ERROR);

if(isset($_SESSION['session_destroyed'][CID])) return '';
switch(self::$session_type) {
case 'file':
$sess_file = rtrim(FILE_SESSION_DIR,'\\/').'/'.FILE_SESSION_TOKEN.$name.'_'.CID;
if(!file_exists($sess_file)) file_put_contents($sess_file,'');
self::$session_client_fp = fopen($sess_file,'r+');
if(!READ_ONLY_SESSION && !flock(self::$session_client_fp,LOCK_EX))
trigger_error('Unable to get lock on session file='.$sess_file,E_USER_ERROR);
$ret = stream_get_contents(self::$session_client_fp);
break;
case 'memcache':
if(!READ_ONLY_SESSION && !self::$memcached->lock(MEMCACHE_SESSION_TOKEN.$name.'_'.CID,self::$memcached_lock_time))
trigger_error('Unable to get lock on session mem='.$name.'_'.CID,E_USER_ERROR);
$ret = '';
for($i=0;; $i++) {
$rr = self::$memcached->get(MEMCACHE_SESSION_TOKEN.$name.'_'.CID.'/'.$i);
if($rr==='' || $rr===false || $rr===null) break;
$ret .= $rr;
}
break;
case 'sql':
$ret = DB::GetCol('SELECT data FROM session_client WHERE session_name = %s AND client_id=%d'.(READ_ONLY_SESSION?'':' FOR UPDATE'), array($name, CID));
if($ret) $ret = $ret[0];
break;
}
if($ret) $_SESSION['client'] = unserialize($ret);
if(isset($_SESSION['session_destroyed'][CID])) return '';
// ----- client session -----
if ($clientData = self::storage()->read($name . '_' . CID))
$_SESSION['client'] = $clientData;

if(!isset($_SESSION['client']['__module_vars__']))
$_SESSION['client']['__module_vars__'] = array();
}
return '';
$_SESSION['client']['__module_vars__'] = $_SESSION['client']['__module_vars__']?? [];
}

public static function write($name, $data) {
public function write($name, $data) {
if(READ_ONLY_SESSION) return true;
$name = self::truncated_session_id($name);
$name = self::truncated_id($name);
if(defined('SESSION_EXPIRED')) {
if(self::$session_type=='memcache') {
if(CID!==false) {
self::$memcached->unlock(MEMCACHE_SESSION_TOKEN.$name.'_'.CID);
}
self::$memcached->unlock(MEMCACHE_SESSION_TOKEN.$name);
}
foreach ([
$name,
$name .'_' . CID
] as $key) {
self::storage()->unlock($key);
}
return true;
}
$ret = 1;
if(CID!==false && isset($_SESSION['client']) && !isset($_SESSION['session_destroyed'][CID])) {
$data = serialize($_SESSION['client']);
switch(self::$session_type) {
case 'file':
ftruncate(self::$session_client_fp, 0); // truncate file
rewind(self::$session_client_fp);
fwrite(self::$session_client_fp, $data);
fflush(self::$session_client_fp); // flush output before releasing the lock
flock(self::$session_client_fp, LOCK_UN); // release the lock
fclose(self::$session_client_fp);
break;
case 'memcache':
if(self::$memcached->is_lock(MEMCACHE_SESSION_TOKEN.$name.'_'.CID,self::$memcached_lock_time)) {
$data = str_split($data,1000000); //something little less then 1MB
$data[] = '';
foreach($data as $i=>$d) {
self::$memcached->set(MEMCACHE_SESSION_TOKEN.$name.'_'.CID.'/'.$i, $d, self::$lifetime);
}
self::$memcached->unlock(MEMCACHE_SESSION_TOKEN.$name.'_'.CID);
}
break;
case 'sql':
if(DB::is_mysql())
$data = DB::qstr($data);
else
$data = '\''.DB::BlobEncode($data).'\'';
$ret &= (bool) DB::Replace('session_client',array('data'=>$data,'session_name'=>DB::qstr($name),'client_id'=>CID),array('session_name','client_id'));
break;
}
}
if(isset($_SESSION['client'])) unset($_SESSION['client']);
$data = serialize($_SESSION);
switch(self::$session_type) {
case 'file':
ftruncate(self::$session_fp, 0); // truncate file
rewind(self::$session_fp);
fwrite(self::$session_fp, $data);
fflush(self::$session_fp); // flush output before releasing the lock
flock(self::$session_fp, LOCK_UN); // release the lock
fclose(self::$session_fp);
$ret &= (bool) DB::Replace('session',array('expires'=>time(),'name'=>DB::qstr($name)),'name');
break;
case 'memcache':
if(self::$memcached->is_lock(MEMCACHE_SESSION_TOKEN.$name,self::$memcached_lock_time)) {
$data = str_split($data,1000000); //something little less then 1MB
$data[] = '';
foreach($data as $i=>$d) {
self::$memcached->set(MEMCACHE_SESSION_TOKEN.$name.'/'.$i, $d, self::$lifetime);
}
self::$memcached->unlock(MEMCACHE_SESSION_TOKEN.$name);
$ret &= (bool) DB::Replace('session',array('expires'=>time(),'name'=>DB::qstr($name)),'name');
}
break;
case 'sql':
if(DB::is_mysql())
$data = DB::qstr($data);
else
$data = '\''.DB::BlobEncode($data).'\'';
$ret &= (bool) DB::Replace('session',array('expires'=>time(),'data'=>$data,'name'=>DB::qstr($name)),'name');
break;
$ret &= self::storage()->write($name . '_' . CID, $_SESSION['client']);
}
unset($_SESSION['client']);
$ret &= self::storage()->write($name, $_SESSION);
$ret &= (bool) DB::Replace('session', [
'expires' => time(),
'name' => DB::qstr($name)
], 'name');

return ($ret>0)?true:false;
return $ret > 0;
}
public static function destroy_client($name,$i) {
$name = self::truncated_session_id($name);
switch(self::$session_type) {
case 'file':
$sess_file = rtrim(FILE_SESSION_DIR,'\\/').'/'.FILE_SESSION_TOKEN.$name.'_'.$i;
@unlink($sess_file);
break;
case 'memcache':
for($k=0;;$k++)
if(!self::$memcached->delete(MEMCACHE_SESSION_TOKEN.$name.'_'.$i.'/'.$k)) break;
self::$memcached->unlock(MEMCACHE_SESSION_TOKEN.$name.'_'.$i);
break;
case 'sql':
DB::Execute('DELETE FROM session_client WHERE session_name=%s AND client_id=%d',array($name,$i));
break;
}
DB::Execute('DELETE FROM history WHERE session_name=%s AND client_id=%d',array($name,$i));
}

public static function destroy($name) {
$name = self::truncated_session_id($name);
public function destroy($name) {
$name = self::truncated_id($name);
$cids = DB::GetCol('SELECT DISTINCT client_id FROM history WHERE session_name=%s',array($name));
foreach($cids as $i)
self::destroy_client($name,$i);
switch(self::$session_type) {
case 'file':
$sess_file = rtrim(FILE_SESSION_DIR,'\\/').'/'.FILE_SESSION_TOKEN.$name;
@unlink($sess_file);
break;
case 'memcache':
for($k=0;;$k++)
if(!self::$memcached->delete(MEMCACHE_SESSION_TOKEN.$name.'/'.$k)) break;
self::$memcached->unlock(MEMCACHE_SESSION_TOKEN.$name);
break;
}
self::storage()->destroy($name);
DB::BeginTrans();
DB::Execute('DELETE FROM history WHERE session_name=%s',array($name));
DB::Execute('DELETE FROM session_client WHERE session_name=%s',array($name));
DB::Execute('DELETE FROM session WHERE name=%s',array($name));
DB::CommitTrans();
return true;
}

public static function gc($lifetime) {
$t = time()-$lifetime;
$ret = DB::Execute('SELECT name FROM session WHERE expires <= %d',array($t));
public function gc($lifetime) {
$before = time() - $lifetime;
$ret = DB::Execute('SELECT name FROM session WHERE expires <= %d', [$before]);
while($row = $ret->FetchRow()) {
self::destroy($row['name']);
}
self::storage()->cleanup($before);

if(FILE_SESSION_DIR) {
$files = @glob(rtrim(FILE_SESSION_DIR,'\\/').'/'.FILE_SESSION_TOKEN.'*');
if(!$files) return true;
foreach($files as $sess_file) {
if(filemtime($sess_file)<$t) @unlink($sess_file);
}
}
return true;
}
}

class EpesiMemcache {
private $memcached = null;
private $mcd = false;
public function __construct() {
if(extension_loaded('memcached')) {
$this->memcached = new Memcached();
$this->mcd = true;
} elseif(extension_loaded('memcache')) {
$this->memcached = new Memcache();
} else {
trigger_error('Missing memcache PHP extension',E_USER_ERROR);
}
}
public function add($key,$var,$exp=null) {
if($this->mcd) return $this->memcached->add($key,$var,$exp);
return $this->memcached->add($key,$var,null,$exp);
}
public function set($key,$var,$exp=null) {
if($this->mcd) return $this->memcached->set($key,$var,$exp);
return $this->memcached->set($key,$var,null,$exp);
}
abstract class EpesiSessionStorage {
protected $lifetime;
public static function factory($class, $lifetime) {
return new $class($lifetime);
}
public function __construct($lifetime) {
$this->setLifetime($lifetime);
}
public static function active() {
return true;
}
public static function tokenize($key) {
return $key;
}
/**
* Read value from storage corresponding to key
*
* @param string $key
*/
abstract public function read($key);
/**
* Write value to storage
*
* @param string $key
* @param mixed $value
*/
abstract public function write($key, $value);
abstract public function destroy($key);
public function lock($key) {}
public function unlock($key) {}
public function cleanup($lifetime) {}
public function getLifetime() {
return $this->lifetime;
}

public function is_lock($key,$exp=null) {
$key .= '#lock';
$v = $this->memcached->get($key);
return $v==$exp || ($exp===null && $v);
}
public function lock($key,$exp) {
$key .= '#lock';
while(!$this->add($key,$exp,$exp) || $this->memcached->get($key)!=$exp) {
if(time()>$exp) return false;
usleep(100);
}
return true;
}
public function unlock($key) {
$this->memcached->delete($key.'#lock');
}
public function __call($f,$a) {
return call_user_func_array(array($this->memcached,$f),$a);
}
public function setLifetime($lifetime) {
$this->lifetime = $lifetime;
return $this;
}
}

class EpesiSessionFileStorage extends EpesiSessionStorage {
protected static $filePointers;
public static function tokenize($name) {
return FILE_SESSION_TOKEN . $name;
}
public function read($name) {
$file = self::getFile($name);
$filePointer = self::getFilePointer($file);
if(!READ_ONLY_SESSION && !flock($filePointer, LOCK_EX))
trigger_error('Unable to get lock on session file=' . $file, E_USER_ERROR);
$ret = stream_get_contents($filePointer);
return $ret? unserialize($ret): '';
}
public function write($name, $data) {
$filePointer = self::getFilePointer(self::getFile($name));
ftruncate($filePointer, 0); // truncate file
rewind($filePointer);
fwrite($filePointer, serialize($data));
fflush($filePointer); // flush output before releasing the lock
flock($filePointer, LOCK_UN); // release the lock
fclose($filePointer);
return true;
}
public function destroy($name) {
@unlink(self::getFile($name));
}
public function cleanup($before) {
if(!FILE_SESSION_DIR) return;
$files = @glob(rtrim(FILE_SESSION_DIR,'\\/'). DIRECTORY_SEPARATOR . FILE_SESSION_TOKEN . '*');
if(!$files) return true;
foreach($files as $file) {
if (filemtime($file) < $before) @unlink($file);
}
}

protected static function getFile($name) {
if(!file_exists(FILE_SESSION_DIR)) mkdir(FILE_SESSION_DIR);
return rtrim(FILE_SESSION_DIR,'\\/') . DIRECTORY_SEPARATOR . self::tokenize($name);
}
protected static function getFilePointer($file) {
if(!file_exists($file)) file_put_contents($file, '');
$key = md5($file);
self::$filePointers[$key] = self::$filePointers[$key]?? fopen($file, 'r+');
return self::$filePointers[$key];
}
}

class EpesiSessionDBStorage extends EpesiSessionStorage {
public function read($name) {
$ret = DB::GetCol('SELECT
data
FROM
session
WHERE
name = %s AND
expires > %d' . (READ_ONLY_SESSION? '': ' FOR UPDATE'), [$name, time() - $this->getLifetime()]);
return $ret? unserialize($ret[0]): '';
}
public function write($name, $data) {
$data = serialize($data);

return (bool) DB::Replace('session', [
'expires' => time(),
'data' => DB::is_mysql()? DB::qstr($data): '\''.DB::BlobEncode($data).'\'',
'name' => DB::qstr($name)
], 'name');
}
public function destroy($name) {
DB::Execute('DELETE FROM session WHERE name=%s', [$name]);
}
}

class EpesiSessionMemcachedStorage extends EpesiSessionStorage {
private $memcached;
private $mcd = false;
private $lockTime;
public static function active() {
return MEMCACHE_SESSION_SERVER? true: false;
}
public static function tokenize($name) {
return MEMCACHE_SESSION_TOKEN . $name;
}
public function __construct($lifetime) {
parent::__construct($lifetime);
if(extension_loaded('memcached')) {
$this->memcached = new Memcached();
$this->mcd = true;
} elseif(extension_loaded('memcache')) {
$this->memcached = new Memcache();
} else {
trigger_error('Missing memcache PHP extension',E_USER_ERROR);
}
$this->lockTime = time() + (ini_get('max_execution_time')?: 60);
$srv = explode(':', MEMCACHE_SESSION_SERVER, 2);
if(!$this->memcached->addServer($srv[0], $srv[1]?? 11211))
trigger_error('Cannot connect to memcache server',E_USER_ERROR);
}
public function read($name) {
$key = self::tokenize($name);
if(!READ_ONLY_SESSION && !$this->lock($key))
trigger_error('Unable to get lock on session mem=' . $name, E_USER_ERROR);
$ret = '';
for($i=0;; $i++) {
$rr = $this->get($key . '/' . $i);
if ($rr==='' || $rr===false || $rr===null) break;
$ret .= $rr;
}
return $ret? unserialize($ret): '';
}
public function write($name, $data) {
$key = self::tokenize($name);
if (!$this->isLocked($key)) $this->lock($key);
$data = str_split(serialize($data), 1000000); //something little less then 1MB
$data[] = '';
foreach($data as $i => $d) {
$this->memcached->set($key . '/' . $i, $d, $this->getLifetime());
}
$this->unlock($key);
return true;
}
public function destroy($name) {
for ($k=0;;$k++) {
if (!$this->memcached->delete(self::tokenize($name) . '/' . $k)) break;
}
$this->unlock(self::tokenize($name));
}
public function add($key, $var, $exp=null) {
if ($this->mcd) return $this->memcached->add($key, $var, $exp);
return $this->memcached->add($key, $var, null, $exp);
}
public function set($key, $var, $exp=null) {
if ($this->mcd) return $this->memcached->set($key, $var, $exp);
return $this->memcached->set($key, $var, null, $exp);
}
public function isLocked($key) {
$key .= '#lock';
$exp = $this->lockTime;
$v = $this->memcached->get($key);
return $v==$exp || ($exp===null && $v);
}
public function lock($key) {
$key .= '#lock';
$exp = $this->lockTime;

while(!$this->add($key, $exp, $exp) || $this->memcached->get($key) != $exp) {
if(time() > $exp) return false;
usleep(100);
}
return true;
}
public function unlock($key) {
$this->memcached->delete($key.'#lock');
}
public function __call($method, $args) {
return call_user_func_array([$this->memcached, $method], $args);
}
}

// remember that even with SET_SESSION = false, class defined below is declared
if(!SET_SESSION) {
global $_SESSION;
if(!isset($_SESSION) || !is_array($_SESSION))
$_SESSION = array();
$_SESSION = [];
return;
}

@@ -335,14 +437,8 @@ if(defined('EPESI_PROCESS')) {
} else {
ini_set('session.gc_probability', 0);
}
ini_set('session.save_handler', 'user');

session_set_save_handler(array('DBSession','open'),
array('DBSession','close'),
array('DBSession','read'),
array('DBSession','write'),
array('DBSession','destroy'),
array('DBSession','gc'));
session_set_save_handler(EpesiSession::create());

if(extension_loaded('apc') || extension_loaded('eaccelerator') || extension_loaded('xcache')) //fix for class DBSession not found
register_shutdown_function('session_write_close');


+ 2
- 0
include/simple_login.php View File

@@ -15,6 +15,8 @@ class SimpleLogin {
return self::t('You have exceeded the number of allowed login attempts.');
}

require_once('modules/Libs/QuickForm/requires.php');

if ((!Base_AclCommon::is_user()) && !$anonymous) {
Base_User_LoginCommon::autologin();
}


+ 130
- 182
index.php View File

@@ -7,17 +7,20 @@
* @author Paul Bukowski <pbukowski@telaxus.com>
* @copyright Copyright &copy; 2006, Telaxus LLC
* @license MIT
* @version 1.0
* @version 1.0
* @package epesi-base
*/
if(version_compare(phpversion(), '5.5.0')==-1)
die("You are running an old version of PHP, php 5.5 required.");
if(version_compare(phpversion(), '7.0.0')==-1)
die("You are running an old version of PHP, php 7.0 required.");

if(trim(ini_get("safe_mode")))
die('You cannot use EPESI with PHP safe mode turned on - please disable it. Please notice this feature is deprecated since PHP 5.3 and will be removed in PHP 7.0.');

define('_VALID_ACCESS',1);
require_once('include/data_dir.php');
define('DATA_DIR','data'); // added by J. Tylek to remove map.php
// Default /data directory location is epesidir/data
// Must be defined here to read config.php

if(!file_exists(DATA_DIR.'/config.php')) {
header('Location: setup.php');
exit();
@@ -37,15 +40,51 @@ if(epesi_requires_update()) {
header('Location: update.php');
exit();
}



$tables = DB::MetaTables();
if(!in_array('modules',$tables) || !in_array('variables',$tables) || !in_array('session',$tables))
die('Database structure you are using is apparently out of date or damaged. If you didn\'t perform application update recently you should try to restore the database. Otherwise, please refer to EPESI documentation in order to perform database update.');

ob_start();

if(IPHONE) {
if(!isset($_GET['force_desktop'])) {
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<meta name="robots" content="NOINDEX, NOARCHIVE">
<meta id="viewport" name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0; user-scalable=0;" />
<title><?php print(EPESI);?></title>
<link rel="stylesheet" href="libs/UiUIKit/stylesheets/iphone.css" />
<link rel="apple-touch-icon" href="images/apple-touch-icon.png" />
<script type="text/javascript" charset="utf-8">
window.onload = function() {
setTimeout(function(){window.scrollTo(0, 1);}, 100);
}
</script>
</head>

<body>
<div id="header">
<h1><?php print(EPESI);?></h1>
</div>

Please choose <?php print(EPESI);?> version:<ul>
<li><a href="mobile.php" class="white button">mobile</a><br>
<li><a href="index.php?force_desktop=1" class="green button">desktop</a>
</ul>

</body>
</html>
<?php
exit();
}
} elseif(detect_mobile_device()) {
header('Location: mobile.php');
exit();
}

?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
@@ -56,195 +95,101 @@ ob_start();
<title><?php print(EPESI);?></title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="SKYPE_TOOLBAR" content="SKYPE_TOOLBAR_PARSER_COMPATIBLE" />
<meta name="SKYPE_TOOLBAR" content="SKYPE_TOOLBAR_PARSER_COMPATIBLE" />
<meta name="robots" content="NOINDEX, NOARCHIVE">
<script type='text/javascript' src='dist/index.js'></script>
<link href='dist/styles.css' rel="stylesheet" type="text/css">
<style type="text/css">

#epesi_loader {
font-weight: 300;
font-size: 15px;
background-color: white;
position: fixed;
left: 50%;
top: 30%;
margin-left: -180px;
width: 360px;
text-align: center;
vertical-align: middle;
z-index: 2002;
overflow: hidden;
padding-top: 20px;
}
#epesi_loader img {
padding: 15px;
}

#epesi_loader .text {
margin-top: 10px;
margin-bottom: 25px;
font-size: 22px;
}

#epesi_loader .spinner {
margin: 20px auto 20px;
text-align: center;
}

#epesi_loader .spinner > div {
width: 18px;
height: 18px;
background-color: #333;

border-radius: 100%;
display: inline-block;
-webkit-animation: sk-bouncedelay 1.4s infinite ease-in-out both;
animation: sk-bouncedelay 1.4s infinite ease-in-out both;
}

#epesi_loader .spinner .bounce1 {
-webkit-animation-delay: -0.32s;
animation-delay: -0.32s;
}

#epesi_loader .spinner .bounce2 {
-webkit-animation-delay: -0.16s;
animation-delay: -0.16s;
}

@-webkit-keyframes sk-bouncedelay {
0%, 80%, 100% { -webkit-transform: scale(0) }
40% { -webkit-transform: scale(1.0) }
}

@keyframes sk-bouncedelay {
0%, 80%, 100% {
-webkit-transform: scale(0);
transform: scale(0);
} 40% {
-webkit-transform: scale(1.0);
transform: scale(1.0);
}
}





.Base_StatusBar_background {
z-index: 2001;
position: fixed;
top: 0px;
left: 0px;
width: 100%;
height: 100%;
text-align: center;
vertical-align: middle;
background-color: rgba(255, 255, 255, 0.5);
}

.Base_StatusBar {
background-color: white;
position: fixed;
left: 50%;
top: 30%;
margin-left: -100px;
width: 200px;
text-align: center;
vertical-align: middle;
z-index: 2002;
overflow: hidden;
padding-top: 20px;
}

.Base_StatusBar .text {
font-size: 22px;
}

.Base_StatusBar .spinner {
margin: 20px auto 20px;
text-align: center;
}

.Base_StatusBar .spinner > div {
width: 18px;
height: 18px;
background-color: #333;

border-radius: 100%;
display: inline-block;
-webkit-animation: sk-bouncedelay 1.4s infinite ease-in-out both;
animation: sk-bouncedelay 1.4s infinite ease-in-out both;
}

.Base_StatusBar .spinner .bounce1 {
-webkit-animation-delay: -0.32s;
animation-delay: -0.32s;
}

.Base_StatusBar .spinner .bounce2 {
-webkit-animation-delay: -0.16s;
animation-delay: -0.16s;
}

@-webkit-keyframes sk-bouncedelay {
0%, 80%, 100% { -webkit-transform: scale(0) }
40% { -webkit-transform: scale(1.0) }
}

@keyframes sk-bouncedelay {
0%, 80%, 100% {
-webkit-transform: scale(0);
transform: scale(0);
} 40% {
-webkit-transform: scale(1.0);
transform: scale(1.0);
}
}

</style>
<?php
ini_set('include_path', 'libs/minify' . PATH_SEPARATOR . '.' . PATH_SEPARATOR . 'libs' . PATH_SEPARATOR . ini_get('include_path'));
require_once('Minify/Build.php');
$jquery = DEBUG_JS ? 'libs/jquery-1.11.3.js' : 'libs/jquery-1.11.3.min.js';
$jquery_migrate = DEBUG_JS ? 'libs/jquery-migrate-1.2.1.js' : 'libs/jquery-migrate-1.2.1.min.js';
$jses = array('libs/prototype.js', $jquery, $jquery_migrate, 'libs/jquery-ui-1.10.1.custom.min.js', 'libs/HistoryKeeper.js', 'include/epesi.js');
if(!DEBUG_JS) {
$jsses_build = new Minify_Build($jses);
$jsses_src = $jsses_build->uri('serve.php?' . http_build_query(array('f' => array_values($jses))));
echo("<script type='text/javascript' src='$jsses_src'></script>");
} else {
foreach($jses as $js)
print("<script type='text/javascript' src='$js'></script>");
}
$csses = array('libs/jquery-ui-1.10.1.custom.min.css');
$csses_build = new Minify_Build($csses);
$csses_src = $csses_build->uri('serve.php?'.http_build_query(array('f'=>array_values($csses))));
?>
<link type="text/css" href="<?php print($csses_src)?>" rel="stylesheet"></link>

<style type="text/css">
<?php if (DIRECTION_RTL) print('body { direction: rtl; }'); ?>
#epesiStatus {
/* Netscape 4, IE 4.x-5.0/Win and other lesser browsers will use this */
position: fixed;
left: 50%; top: 30%;
margin-left: -280px;
/* all */
/*background-color: #e6ecf2;*/
background-color: white;
border: 5px solid #336699;
visibility: hidden;
width: 560px;
text-align: center;
vertical-align: middle;
z-index: 2002;
color: #336699;
overflow: hidden;
/* css3 shadow border*/
-webkit-box-shadow: 1px 1px 15px black;
-moz-box-shadow: 1px 1px 15px black;
box-shadow: 1px 1px 15px black;
/* end css3 shadow border*/
/* border radius */
-webkit-border-radius: 6px;
-moz-border-radius: 6px;
border-radius: 6px;
/* end border radius */
}
#epesiStatus table {
color: #336699;
font-weight: bold;
font-family: Tahoma, Verdana, Vera-Sans, DejaVu-Sans;
font-size: 11px;
border: 5px solid #FFFFFF;
}

</style>
<?php print(TRACKING_CODE); ?>
</head>
<body class="<?php if (DIRECTION_RTL) print(' epesi_rtl'); ?>" >
<body <?php if (DIRECTION_RTL) print('class="epesi_rtl"'); ?> >

<div id="body_content" class="page">
<div id="main_content" class="page-main" style="display:none;"></div>
<div id="body_content">
<div id="main_content" style="display:none;"></div>
<div id="debug_content" style="padding-top:97px;display:none;">
<div class="button" onclick="jq('#error_box').html('');jq('#debug_content').hide();">Hide</div>
<div class="button" onclick="$('error_box').innerHTML='';$('debug_content').style.display='none';">Hide</div>
<div id="debug"></div>
<div id="error_box"></div>
</div>

<div id="epesi_loader" class="panel panel-default">
<img src="images/epesi_logo_RGB_Solid.png">
<div class="lead text" id="epesiStatusText"><?php print(STARTING_MESSAGE);?></div>
<div class="spinner">
<div class="bounce1"></div>
<div class="bounce2"></div>
<div class="bounce3"></div>
</div>
</div>
<div id="Base_StatusBar" class="Base_StatusBar_background">
<div class="Base_StatusBar panel panel-default">
<p id="statusbar_text" class="lead">Loading...</p>
<div class="spinner">
<div class="bounce1"></div>
<div class="bounce2"></div>
<div class="bounce3"></div>
</div>
<div id="dismiss">Click anywhere to dismiss</div>
</div>
</div>
<div id="epesiStatus">
<table cellspacing="0" cellpadding="0" border="0" style="width: 100%;">
<tr>
<td><img src="images/logo.png" alt="logo" width="550" height="200" border="0"></td>
</tr>
<tr>
<td style="text-align: center; vertical-align: middle; height: 30px;"><span id="epesiStatusText"><?php print(STARTING_MESSAGE);?></span></td>
</tr>
<tr>
<td style="text-align: center; vertical-align: middle; height: 30px;"><img src="images/loader.gif" alt="loader" width="256" height="10" border="0"></td>
</tr>
</table>
</div>
</div>
<?php
<?php
/*
* init_js file allows only num_of_clients sessions. If there is image
* with empty src="" browser will load index.php file, so we cannot
* include init_js file directly because num_of_clients request will
* reset our history and restart EPESI.
*
*
* Check here if request accepts html. If it does we can assume that
* this is request for page and include init_js file which is faster.
* If there is not 'html' in accept use script with src property.
@@ -255,6 +200,9 @@ ob_start();
<script type="text/javascript" src="init_js.php?<?php print(http_build_query($_GET));?>"></script>
<?php } ?>
<noscript>Please enable JavaScript in your browser and let <?php print(EPESI);?> work!</noscript>
<?php if(IPHONE) { ?>
<script type="text/javascript">var iphone=true;</script>
<?php } ?>
</body>
</html>
<?php


+ 2
- 2
init_js.php View File

@@ -30,9 +30,9 @@ $_SESSION['num_of_clients'] = $client_id_next;

//DBSession::destroy_client(session_id(),$client_id);
if($client_id-5>=0) {
DBSession::destroy_client(session_id(),$client_id-5);
EpesiSession::destroy_client(session_id(),$client_id-5);
$_SESSION['session_destroyed'][$client_id-5] = 1;
}
session_commit();

?>window.Epesi = new EpesiClass(<?php print($client_id); ?>,'<?php print(rtrim(str_replace('\\','/',dirname($_SERVER['PHP_SELF'])),'/').'/process.php'); ?>','<?php print(http_build_query($_GET));?>');
?>Epesi.init(<?php print($client_id); ?>,'<?php print(rtrim(str_replace('\\','/',dirname($_SERVER['PHP_SELF'])),'/').'/process.php'); ?>','<?php print(http_build_query($_GET));?>');

+ 0
- 5
libs/bootstrap-datetimepicker.min.css
File diff suppressed because it is too large
View File


+ 0
- 2
libs/bootstrap-datetimepicker.min.js
File diff suppressed because it is too large
View File


BIN
libs/images/ui-icons_444444_256x240.png View File

Before After
Width: 256  |  Height: 240  |  Size: 6.8 KiB

BIN
libs/images/ui-icons_555555_256x240.png View File

Before After
Width: 256  |  Height: 240  |  Size: 6.8 KiB

BIN
libs/images/ui-icons_777620_256x240.png View File

Before After
Width: 256  |  Height: 240  |  Size: 4.4 KiB

BIN
libs/images/ui-icons_777777_256x240.png View File

Before After
Width: 256  |  Height: 240  |  Size: 6.8 KiB

BIN
libs/images/ui-icons_cc0000_256x240.png View File

Before After
Width: 256  |  Height: 240  |  Size: 4.4 KiB

BIN
libs/images/ui-icons_ffffff_256x240.png View File

Before After
Width: 256  |  Height: 240  |  Size: 6.2 KiB

+ 0
- 117
libs/jquery.clonePosition.js View File

@@ -1,117 +0,0 @@
(function($){

function setOffset(el, newOffset){
var $el = $(el);

// get the current css position of the element
var cssPosition = $el.css('position');

// whether or not element is hidden
var hidden = false;

// if element was hidden, show it
if($el.css('display') == 'none'){
hidden = true;
$el.show();
}

// get the current offset of the element
var curOffset = $el.offset();

// if there is no current jQuery offset, give up
if(!curOffset){
// if element was hidden, hide it again
if(hidden)
$el.hide();
return;
}

// set position to relative if it's static
if (cssPosition == 'static') {
$el.css('position', 'relative');
cssPosition = 'relative';
}

// get current 'left' and 'top' values from css
// this is not necessarily the same as the jQuery offset
var delta = {
left : parseInt($el.css('left'), 10),
top: parseInt($el.css('top'), 10)
};

// if the css left or top are 'auto', they aren't numbers
if (isNaN(delta.left)){
delta.left = (cssPosition == 'relative') ? 0 : el.offsetLeft;
}
if (isNaN(delta.top)){
delta.top = (cssPosition == 'relative') ? 0 : el.offsetTop;
}

if (newOffset.left || 0 === newOffset.left){
$el.css('left', newOffset.left - curOffset.left + delta.left + 'px');
}
if (newOffset.top || 0 === newOffset.top){
$el.css('top', newOffset.top - curOffset.top + delta.top + 'px');
}

// if element was hidden, hide it again
if(hidden)
$el.hide();
}

$.fn.extend({

/**
* Store the original version of offset(), so that we don't lose it
*/
_offset : $.fn.offset,

/**
* Set or get the specific left and top position of the matched
* elements, relative the the browser window by calling setXY