mirror of
https://github.com/Karaka-Management/phpOMS.git
synced 2026-01-11 09:48:40 +00:00
autoloader loading guard, cache flush fix, transactions, ALT datamapper loading, table linter fix, session handling for caches, file path guard, image diff, directory delete guard, general localization model, office parsers
This commit is contained in:
parent
1bc05c79d6
commit
de1bf517c2
34
Application/ApplicationType.php
Normal file
34
Application/ApplicationType.php
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
/**
|
||||
* Karaka
|
||||
*
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Application
|
||||
* @copyright Dennis Eichhorn
|
||||
* @license OMS License 1.0
|
||||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace phpOMS\Application;
|
||||
|
||||
use phpOMS\Stdlib\Base\Enum;
|
||||
|
||||
/**
|
||||
* App status enum.
|
||||
*
|
||||
* @package phpOMS\Application
|
||||
* @license OMS License 1.0
|
||||
* @link https://jingga.app
|
||||
* @since 1.0.0
|
||||
*/
|
||||
abstract class ApplicationType extends Enum
|
||||
{
|
||||
public const WEB = 1;
|
||||
|
||||
public const CONSOLE = 2;
|
||||
|
||||
public const SOCKET = 3;
|
||||
}
|
||||
|
|
@ -60,6 +60,20 @@ final class Autoloader
|
|||
self::$paths[] = \rtrim($path, '/\\') . '/';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a path is already in the path list
|
||||
*
|
||||
* @param string $path Absolute base path with / at the end
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public static function inPaths(string $path) : bool
|
||||
{
|
||||
return \in_array(\rtrim($path, '/\\') . '/', self::$paths);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find include paths for class
|
||||
*
|
||||
|
|
|
|||
|
|
@ -280,7 +280,7 @@ final class MemCached extends ConnectionAbstract
|
|||
return false;
|
||||
}
|
||||
|
||||
return $this->flushAll();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -305,7 +305,7 @@ final class RedisCache extends ConnectionAbstract
|
|||
return false;
|
||||
}
|
||||
|
||||
return $this->flushDb();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -213,4 +213,25 @@ abstract class ConnectionAbstract implements ConnectionInterface
|
|||
|
||||
return isset($this->{$name}) ? $this->{$name} : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start a transaction
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
abstract public function beginTransaction() : void;
|
||||
|
||||
/**
|
||||
* Roll back a transaction
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
abstract public function rollBack() : void;
|
||||
|
||||
/**
|
||||
* Commit a transaction
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
abstract public function commit() : void;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -87,4 +87,28 @@ final class MysqlConnection extends ConnectionAbstract
|
|||
$this->dbdata['password'] = '****';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function beginTransaction() : void
|
||||
{
|
||||
$this->con->beginTransaction();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function rollBack() : void
|
||||
{
|
||||
$this->con->rollBack();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function commit() : void
|
||||
{
|
||||
$this->con->commit();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,4 +38,25 @@ final class NullConnection extends ConnectionAbstract
|
|||
{
|
||||
return ['id' => $this->id];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function beginTransaction() : void
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function rollBack() : void
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function commit() : void
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -88,4 +88,28 @@ final class PostgresConnection extends ConnectionAbstract
|
|||
$this->dbdata['password'] = '****';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function beginTransaction() : void
|
||||
{
|
||||
$this->con->beginTransaction();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function rollBack() : void
|
||||
{
|
||||
$this->con->rollBack();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function commit() : void
|
||||
{
|
||||
$this->con->commit();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -98,4 +98,28 @@ final class SQLiteConnection extends ConnectionAbstract
|
|||
$this->dbdata['password'] = '****';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function beginTransaction() : void
|
||||
{
|
||||
$this->con->beginTransaction();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function rollBack() : void
|
||||
{
|
||||
$this->con->rollBack();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function commit() : void
|
||||
{
|
||||
$this->con->commit();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -88,4 +88,28 @@ final class SqlServerConnection extends ConnectionAbstract
|
|||
$this->dbdata['password'] = '****';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function beginTransaction() : void
|
||||
{
|
||||
$this->con->beginTransaction();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function rollBack() : void
|
||||
{
|
||||
$this->con->rollBack();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function commit() : void
|
||||
{
|
||||
$this->con->commit();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -324,23 +324,25 @@ final class ReadMapper extends DataMapperAbstract
|
|||
// Example: Show all profiles who have written a news article.
|
||||
// "with()" only allows to go from articles to accounts but we want to go the other way
|
||||
foreach ($this->join as $member => $values) {
|
||||
if (($col = $this->mapper::getColumnByMember($member)) !== null) {
|
||||
/* variable in model */
|
||||
foreach ($values as $join) {
|
||||
// @todo: the has many, etc. if checks only work if it is a relation on the first level, if we have a deeper where condition nesting this fails
|
||||
if ($join['child'] !== '') {
|
||||
continue;
|
||||
}
|
||||
if (($col = $this->mapper::getColumnByMember($member)) === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$query->join($join['mapper']::TABLE, $join['type'], $join['mapper']::TABLE . '_d' . ($this->depth + 1))
|
||||
->on(
|
||||
$this->mapper::TABLE . '_d' . $this->depth . '.' . $col,
|
||||
'=',
|
||||
$join['mapper']::TABLE . '_d' . ($this->depth + 1) . '.' . $join['mapper']::getColumnByMember($join['value']),
|
||||
'and',
|
||||
$join['mapper']::TABLE . '_d' . ($this->depth + 1)
|
||||
);
|
||||
/* variable in model */
|
||||
foreach ($values as $join) {
|
||||
// @todo: the has many, etc. if checks only work if it is a relation on the first level, if we have a deeper where condition nesting this fails
|
||||
if ($join['child'] !== '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$query->join($join['mapper']::TABLE, $join['type'], $join['mapper']::TABLE . '_d' . ($this->depth + 1))
|
||||
->on(
|
||||
$this->mapper::TABLE . '_d' . $this->depth . '.' . $col,
|
||||
'=',
|
||||
$join['mapper']::TABLE . '_d' . ($this->depth + 1) . '.' . $join['mapper']::getColumnByMember($join['value']),
|
||||
'and',
|
||||
$join['mapper']::TABLE . '_d' . ($this->depth + 1)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -354,7 +356,13 @@ final class ReadMapper extends DataMapperAbstract
|
|||
}
|
||||
|
||||
if (($col = $this->mapper::getColumnByMember($member)) !== null) {
|
||||
// In case alternative where values are allowed
|
||||
// This is different from normal or conditions as these are exclusive or conditions
|
||||
// This means they are only selected IFF the previous where clause fails
|
||||
$alt = [];
|
||||
|
||||
/* variable in model */
|
||||
$previous = null;
|
||||
foreach ($values as $where) {
|
||||
// @todo: the has many, etc. if checks only work if it is a relation on the first level, if we have a deeper where condition nesting this fails
|
||||
if ($where['child'] !== '') {
|
||||
|
|
@ -362,74 +370,44 @@ final class ReadMapper extends DataMapperAbstract
|
|||
}
|
||||
|
||||
$comparison = \is_array($where['value']) && \count($where['value']) > 1 ? 'in' : $where['logic'];
|
||||
$query->where($this->mapper::TABLE . '_d' . $this->depth . '.' . $col, $comparison, $where['value'], $where['comparison']);
|
||||
}
|
||||
} /* elseif (isset($this->mapper::HAS_MANY[$member])) {
|
||||
// variable in has many
|
||||
// @todo: maybe needed in the future, but needs adjustment, doesn't make sense at the moment
|
||||
foreach ($values as $where) {
|
||||
// @todo: the has many, etc. if checks only work if it is a relation on the first level, if we have a deeper where condition nesting this fails
|
||||
if ($where['child'] !== '') {
|
||||
continue;
|
||||
}
|
||||
if ($where['comparison'] === 'ALT') {
|
||||
// This uses an alternative value if the previous value(s) in the where clause don't exist (e.g. for localized results where you allow a user language, alternatively a primary language, and then alternatively any language if the first two don't exist).
|
||||
|
||||
$comparison = \is_array($where['value']) && \count($where['value']) > 1 ? 'in' : $where['logic'];
|
||||
$query->where($this->mapper::HAS_MANY[$member]['table'] . '_d' . $this->depth . '.' . $this->mapper::HAS_MANY[$member]['external'], $comparison, $where['value'], $where['comparison']);
|
||||
// is first value
|
||||
if (empty($alt)) {
|
||||
$alt[] = $previous['value'];
|
||||
}
|
||||
|
||||
$query->leftJoin($this->mapper::HAS_MANY[$member]['table'], $this->mapper::HAS_MANY[$member]['table'] . '_d' . $this->depth);
|
||||
if ($this->mapper::HAS_MANY[$member]['external'] !== null) {
|
||||
$query->on(
|
||||
$this->mapper::TABLE . '_d' . $this->depth . '.' . $this->mapper::HAS_MANY[$member][$this->mapper::PRIMARYFIELD], '=',
|
||||
$this->mapper::HAS_MANY[$member]['table'] . '_d' . $this->depth . '.' . $this->mapper::HAS_MANY[$member]['self'], 'AND',
|
||||
$this->mapper::HAS_MANY[$member]['table'] . '_d' . $this->depth
|
||||
);
|
||||
/*
|
||||
select * from table_name
|
||||
where // where starts here
|
||||
field1 = 'value1' // comes from normal where
|
||||
or ( // where1 starts here
|
||||
field1 = 'default'
|
||||
and NOT EXISTS ( // where2 starts here
|
||||
select 1 from table_name where field1 = 'value1'
|
||||
)
|
||||
)
|
||||
*/
|
||||
$where1 = new Where($query->db);
|
||||
$where1->where($this->mapper::TABLE . '_d' . $this->depth . '.' . $col, $comparison, $where['value'], 'and');
|
||||
|
||||
$where2 = new Builder($query->db);
|
||||
$where2->select('1')
|
||||
->from($this->mapper::TABLE . '_d' . $this->depth)
|
||||
->where($this->mapper::TABLE . '_d' . $this->depth . '.' . $col, 'in', $alt);
|
||||
|
||||
$where1->where($this->mapper::TABLE . '_d' . $this->depth . '.' . $col, 'not exists', $where2, 'and');
|
||||
|
||||
$query->where($this->mapper::TABLE . '_d' . $this->depth . '.' . $col, $comparison, $where1, 'or');
|
||||
|
||||
$alt[] = $where['value'];
|
||||
} else {
|
||||
$query->on(
|
||||
$this->mapper::TABLE . '_d' . $this->depth . '.' . $this->mapper::PRIMARYFIELD, '=',
|
||||
$this->mapper::HAS_MANY[$member]['table'] . '_d' . $this->depth . '.' . $this->mapper::HAS_MANY[$member]['self'], 'AND',
|
||||
$this->mapper::HAS_MANY[$member]['table'] . '_d' . $this->depth
|
||||
);
|
||||
$previous = $where;
|
||||
$query->where($this->mapper::TABLE . '_d' . $this->depth . '.' . $col, $comparison, $where['value'], $where['comparison']);
|
||||
}
|
||||
}
|
||||
|
||||
} */ /* elseif (isset($this->mapper::BELONGS_TO[$member])) {
|
||||
// variable in belogns to
|
||||
// @todo: maybe needed in the future, but needs adjustment, doesn't make sense at the moment
|
||||
foreach ($values as $index => $where) {
|
||||
// @todo: the has many, etc. if checks only work if it is a relation on the first level, if we have a deeper where condition nesting this fails
|
||||
if ($where['child'] !== '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$comparison = \is_array($where['value']) && \count($where['value']) > 1 ? 'in' : $where['logic'];
|
||||
$query->where($this->mapper::TABLE . '_d' . $this->depth . '.' . $member, $comparison, $where['value'], $where['comparison']);
|
||||
|
||||
$query->leftJoin($this->mapper::BELONGS_TO[$member]['mapper']::TABLE, $this->mapper::BELONGS_TO[$member]['mapper']::TABLE . '_d' . $this->depth)
|
||||
->on(
|
||||
$this->mapper::TABLE . '_d' . $this->depth . '.' . $this->mapper::BELONGS_TO[$member]['external'], '=',
|
||||
$this->mapper::BELONGS_TO[$member]['mapper']::TABLE . '_d' . $this->depth . '.' . $this->mapper::BELONGS_TO[$member]['mapper']::PRIMARYFIELD , 'AND',
|
||||
$this->mapper::BELONGS_TO[$member]['mapper']::TABLE . '_d' . $this->depth
|
||||
);
|
||||
}
|
||||
} */ /* elseif (isset($this->mapper::OWNS_ONE[$member])) {
|
||||
// variable in owns one
|
||||
// @todo: maybe needed in the future, but needs adjustment, doesn't make sense at the moment
|
||||
foreach ($values as $index => $where) {
|
||||
// @todo: the has many, etc. if checks only work if it is a relation on the first level, if we have a deeper where condition nesting this fails
|
||||
if ($where['child'] !== '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$comparison = \is_array($where['value']) && \count($where['value']) > 1 ? 'in' : $where['logic'];
|
||||
$query->where($this->mapper::TABLE . '_d' . $this->depth . '.' . $member, $comparison, $where['value'], $where['comparison']);
|
||||
$query->leftJoin($this->mapper::OWNS_ONE[$member]['mapper']::TABLE, $this->mapper::OWNS_ONE[$member]['mapper']::TABLE . '_d' . $this->depth)
|
||||
->on(
|
||||
$this->mapper::TABLE . '_d' . $this->depth . '.' . $this->mapper::OWNS_ONE[$member]['external'], '=',
|
||||
$this->mapper::OWNS_ONE[$member]['mapper']::TABLE . '_d' . $this->depth . '.' . $this->mapper::OWNS_ONE[$member]['mapper']::PRIMARYFIELD , 'AND',
|
||||
$this->mapper::OWNS_ONE[$member]['mapper']::TABLE . '_d' . $this->depth
|
||||
);
|
||||
}
|
||||
} */
|
||||
}
|
||||
}
|
||||
|
||||
// load relations
|
||||
|
|
|
|||
|
|
@ -305,13 +305,13 @@ class Grammar extends GrammarAbstract
|
|||
/**
|
||||
* Compile column query.
|
||||
*
|
||||
* @param column $column Where query
|
||||
* @param Column $column Where query
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
protected function compileColumnQuery(column $column) : string
|
||||
protected function compileColumnQuery(Column $column) : string
|
||||
{
|
||||
return $column->toSql();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,15 +3,15 @@
|
|||
"name": "[a-z\\_]+",
|
||||
"fields": {
|
||||
".*": {
|
||||
"name": "[a-z\\_]+",
|
||||
"name": "[a-z0-9\\_]+",
|
||||
"type": "[A-Z0-9\\(\\)]+",
|
||||
".*?default": ".*",
|
||||
".*?null": "1|0",
|
||||
".*?primary": "1|0",
|
||||
".*?unique": "1|0",
|
||||
".*?autoincrement": "1|0",
|
||||
".*?foreignTable": "[a-z\\_]+",
|
||||
".*?foreignKey": "[a-z\\_]+",
|
||||
".*?foreignTable": "[a-z0-9\\_]+",
|
||||
".*?foreignKey": "[a-z0-9\\_]+",
|
||||
".*?annotations": ".*"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
75
DataStorage/Session/FileSessionHandler.php → DataStorage/Session/CacheSessionHandler.php
Executable file → Normal file
75
DataStorage/Session/FileSessionHandler.php → DataStorage/Session/CacheSessionHandler.php
Executable file → Normal file
|
|
@ -14,8 +14,11 @@ declare(strict_types=1);
|
|||
|
||||
namespace phpOMS\DataStorage\Session;
|
||||
|
||||
use phpOMS\DataStorage\Cache\Connection\ConnectionAbstract;
|
||||
use phpOMS\DataStorage\Cache\CacheStatus;
|
||||
|
||||
/**
|
||||
* File session handler.
|
||||
* Cache session handler.
|
||||
*
|
||||
* @package phpOMS\DataStorage\Session
|
||||
* @license OMS License 1.0
|
||||
|
|
@ -24,30 +27,35 @@ namespace phpOMS\DataStorage\Session;
|
|||
*
|
||||
* @SuppressWarnings(PHPMD.Superglobals)
|
||||
*/
|
||||
final class FileSessionHandler implements \SessionHandlerInterface, \SessionIdInterface
|
||||
final class CacheSessionHandler implements \SessionHandlerInterface, \SessionIdInterface
|
||||
{
|
||||
/**
|
||||
* File path for session
|
||||
* Cache connection
|
||||
*
|
||||
* @var string
|
||||
* @var ConnectionAbstract
|
||||
* @since 1.0.0
|
||||
*/
|
||||
private string $savePath;
|
||||
private ConnectionAbstract $con;
|
||||
|
||||
/**
|
||||
* Expiration time
|
||||
*
|
||||
* @var int
|
||||
* @since 1.0.0
|
||||
*/
|
||||
private int $expire = 3600;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $path Path of the session data
|
||||
* @param ConnectionAbstract $con ConnectionAbstract
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function __construct(string $path)
|
||||
public function __construct(ConnectionAbstract $con, int $expire = 3600)
|
||||
{
|
||||
$this->savePath = $path;
|
||||
|
||||
if (\realpath($path) === false) {
|
||||
\mkdir($path, 0755, true);
|
||||
}
|
||||
$this->con = $con;
|
||||
$this->expire = $expire;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -74,13 +82,15 @@ final class FileSessionHandler implements \SessionHandlerInterface, \SessionIdIn
|
|||
*/
|
||||
public function open(string $savePath, string $sessionName) : bool
|
||||
{
|
||||
$this->savePath = $savePath;
|
||||
if ($con->getStatus() !== CacheStatus::OK) {
|
||||
$con->connect();
|
||||
}
|
||||
|
||||
return \is_dir($this->savePath);
|
||||
return $con->getStatus() === CacheStatus::OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the session
|
||||
* Closing the cache connection doesn't happen in here and must be implemented in the application
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
|
|
@ -92,7 +102,7 @@ final class FileSessionHandler implements \SessionHandlerInterface, \SessionIdIn
|
|||
}
|
||||
|
||||
/**
|
||||
* Read the session data
|
||||
* Read the session data (also prolongs the expire)
|
||||
*
|
||||
* @param string $id Session id
|
||||
*
|
||||
|
|
@ -102,11 +112,15 @@ final class FileSessionHandler implements \SessionHandlerInterface, \SessionIdIn
|
|||
*/
|
||||
public function read(string $id) : string|false
|
||||
{
|
||||
if (!\is_file($this->savePath . '/sess_' . $id)) {
|
||||
return '';
|
||||
$data = $this->con->get($id);
|
||||
|
||||
if ($data === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return \file_get_contents($this->savePath . '/sess_' . $id);
|
||||
$this->con->updateExpire($this->expire);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -121,7 +135,9 @@ final class FileSessionHandler implements \SessionHandlerInterface, \SessionIdIn
|
|||
*/
|
||||
public function write(string $id, string $data) : bool
|
||||
{
|
||||
return \file_put_contents($this->savePath . '/sess_' . $id, $data) === false ? false : true;
|
||||
$this->con->set($id, $data, -1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -135,10 +151,7 @@ final class FileSessionHandler implements \SessionHandlerInterface, \SessionIdIn
|
|||
*/
|
||||
public function destroy(string $id) : bool
|
||||
{
|
||||
$file = $this->savePath . '/sess_' . $id;
|
||||
if (\is_file($file)) {
|
||||
\unlink($file);
|
||||
}
|
||||
$this->con->delete($id);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -154,18 +167,6 @@ final class FileSessionHandler implements \SessionHandlerInterface, \SessionIdIn
|
|||
*/
|
||||
public function gc(int $maxlifetime) : int|false
|
||||
{
|
||||
$files = \glob("{$this->savePath}/sess_*");
|
||||
|
||||
if ($files === false) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
foreach ($files as $file) {
|
||||
if (\filemtime($file) + $maxlifetime < \time() && \is_file($file)) {
|
||||
\unlink($file);
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
(int) $this->con->flush($maxlifetime);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,219 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* Karaka
|
||||
*
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\DataStorage\Session
|
||||
* @copyright Dennis Eichhorn
|
||||
* @license OMS License 1.0
|
||||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace phpOMS\DataStorage\Session;
|
||||
|
||||
use phpOMS\DataStorage\LockException;
|
||||
|
||||
/**
|
||||
* File session class.
|
||||
*
|
||||
* @package phpOMS\DataStorage\Session
|
||||
* @license OMS License 1.0
|
||||
* @link https://jingga.app
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @SuppressWarnings(PHPMD.Superglobals)
|
||||
*/
|
||||
class FileSession implements SessionInterface
|
||||
{
|
||||
/**
|
||||
* Is session locked/already set.
|
||||
*
|
||||
* @var bool
|
||||
* @since 1.0.0
|
||||
*/
|
||||
private bool $isLocked = false;
|
||||
|
||||
/**
|
||||
* Raw session data.
|
||||
*
|
||||
* @var array<string, mixed>
|
||||
* @since 1.0.0
|
||||
*/
|
||||
private array $sessionData = [];
|
||||
|
||||
/**
|
||||
* Session ID.
|
||||
*
|
||||
* @var string
|
||||
* @since 1.0.0
|
||||
*/
|
||||
private string $sid;
|
||||
|
||||
/**
|
||||
* Inactivity Interval.
|
||||
*
|
||||
* @var int
|
||||
* @since 1.0.0
|
||||
*/
|
||||
private int $inactivityInterval = 0;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param int $liftetime Session life time
|
||||
* @param string $sid Session id
|
||||
* @param int $inactivityInterval Interval for session activity
|
||||
*
|
||||
* @throws LockException throws this exception if the session is alrady locked for further interaction
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function __construct(int $liftetime = 3600, string $sid = '', int $inactivityInterval = 0)
|
||||
{
|
||||
if (\session_id()) {
|
||||
\session_write_close(); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
if ($sid !== '') {
|
||||
\session_id((string) $sid);
|
||||
}
|
||||
|
||||
$this->inactivityInterval = $inactivityInterval;
|
||||
|
||||
if (\session_status() !== \PHP_SESSION_ACTIVE && !\headers_sent()) {
|
||||
// @codeCoverageIgnoreStart
|
||||
\session_set_cookie_params($liftetime, '/', '', false, true);
|
||||
\session_start();
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
if ($this->inactivityInterval > 0
|
||||
&& ($this->inactivityInterval + ($_SESSION['lastActivity'] ?? 0) < \time())
|
||||
) {
|
||||
$this->destroy(); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
$this->sessionData = $_SESSION ?? [];
|
||||
$_SESSION = null;
|
||||
$this->sessionData['lastActivity'] = \time();
|
||||
$this->sid = (string) \session_id();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function set(string $key, mixed $value, bool $overwrite = false) : bool
|
||||
{
|
||||
if (!$this->isLocked && ($overwrite || !isset($this->sessionData[$key]))) {
|
||||
$this->sessionData[$key] = $value;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get(string $key) : mixed
|
||||
{
|
||||
return $this->sessionData[$key] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function lock() : void
|
||||
{
|
||||
$this->isLocked = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if session is locked.
|
||||
*
|
||||
* @return bool Lock status
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function isLocked() : bool
|
||||
{
|
||||
return $this->isLocked;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function save() : bool
|
||||
{
|
||||
if ($this->isLocked) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$_SESSION = $this->sessionData;
|
||||
\session_write_close();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function remove(string $key) : bool
|
||||
{
|
||||
if (!$this->isLocked && isset($this->sessionData[$key])) {
|
||||
unset($this->sessionData[$key]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getSID() : string
|
||||
{
|
||||
return $this->sid;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setSID(string $sid) : void
|
||||
{
|
||||
$this->sid = $sid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy the current session.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
private function destroy() : void
|
||||
{
|
||||
if (\session_status() !== \PHP_SESSION_NONE) {
|
||||
\session_destroy();
|
||||
$this->sessionData = [];
|
||||
\session_start();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Destruct session.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
$this->save();
|
||||
}
|
||||
}
|
||||
|
|
@ -98,7 +98,9 @@ final class HttpSession implements SessionInterface
|
|||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
if ($this->inactivityInterval > 0 && ($this->inactivityInterval + ($_SESSION['lastActivity'] ?? 0) < \time())) {
|
||||
if ($this->inactivityInterval > 0
|
||||
&& ($this->inactivityInterval + ($_SESSION['lastActivity'] ?? 0) < \time())
|
||||
) {
|
||||
$this->destroy(); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
# Session #
|
||||
183
Localization/BaseStringL11n.php
Normal file
183
Localization/BaseStringL11n.php
Normal file
|
|
@ -0,0 +1,183 @@
|
|||
<?php
|
||||
/**
|
||||
* Karaka
|
||||
*
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Localization
|
||||
* @copyright Dennis Eichhorn
|
||||
* @license OMS License 1.0
|
||||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace phpOMS\Localization;
|
||||
|
||||
use phpOMS\Localization\ISO639x1Enum;
|
||||
use phpOMS\Localization\ISO3166TwoEnum;
|
||||
|
||||
/**
|
||||
* String l11n class.
|
||||
*
|
||||
* @package phpOMS\Localization
|
||||
* @license OMS License 1.0
|
||||
* @link https://jingga.app
|
||||
* @since 1.0.0
|
||||
*/
|
||||
class BaseStringL11n implements \JsonSerializable
|
||||
{
|
||||
/**
|
||||
* ID.
|
||||
*
|
||||
* @var int
|
||||
* @since 1.0.0
|
||||
*/
|
||||
protected int $id = 0;
|
||||
|
||||
/**
|
||||
* Name.
|
||||
*
|
||||
* @var string
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public string $name = '';
|
||||
|
||||
/**
|
||||
* Ref.
|
||||
*
|
||||
* @var int
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public int $ref = 0;
|
||||
|
||||
/**
|
||||
* Language.
|
||||
*
|
||||
* @var string
|
||||
* @since 1.0.0
|
||||
*/
|
||||
protected string $language = ISO639x1Enum::_EN;
|
||||
|
||||
/**
|
||||
* Country.
|
||||
*
|
||||
* @var string
|
||||
* @since 1.0.0
|
||||
*/
|
||||
protected string $country = ISO3166TwoEnum::_USA;
|
||||
|
||||
/**
|
||||
* Content.
|
||||
*
|
||||
* @var string
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public string $content = '';
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $content Localized content
|
||||
* @param string $language Language
|
||||
* @param string $country Country
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function __construct(
|
||||
string $content = '',
|
||||
string $language = ISO639x1Enum::_EN,
|
||||
string $country = ISO3166TwoEnum::_USA
|
||||
)
|
||||
{
|
||||
$this->content = $content;
|
||||
$this->language = $language;
|
||||
$this->country = $country;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get id
|
||||
*
|
||||
* @return int
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function getId() : int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get language
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function getLanguage() : string
|
||||
{
|
||||
return $this->language;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set language
|
||||
*
|
||||
* @param string $language Language
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function setLanguage(string $language) : void
|
||||
{
|
||||
$this->language = $language;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get country
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function getCountry() : string
|
||||
{
|
||||
return $this->country;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set country
|
||||
*
|
||||
* @param string $country Country
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function setCountry(string $country) : void
|
||||
{
|
||||
$this->country = $country;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function toArray() : array
|
||||
{
|
||||
return [
|
||||
'id' => $this->id,
|
||||
'content' => $this->content,
|
||||
'ref' => $this->ref,
|
||||
'language' => $this->language,
|
||||
'country' => $this->country,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function jsonSerialize() : mixed
|
||||
{
|
||||
return $this->toArray();
|
||||
}
|
||||
}
|
||||
47
Localization/NullBaseStringL11n.php
Normal file
47
Localization/NullBaseStringL11n.php
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
<?php
|
||||
/**
|
||||
* Karaka
|
||||
*
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Localization
|
||||
* @copyright Dennis Eichhorn
|
||||
* @license OMS License 1.0
|
||||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace phpOMS\Localization;
|
||||
|
||||
/**
|
||||
* Null model
|
||||
*
|
||||
* @package phpOMS\Localization
|
||||
* @license OMS License 1.0
|
||||
* @link https://jingga.app
|
||||
* @since 1.0.0
|
||||
*/
|
||||
final class NullBaseStringL11n extends BaseStringL11n
|
||||
{
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param int $id Model id
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function __construct(int $id = 0)
|
||||
{
|
||||
$this->id = $id;
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function jsonSerialize() : mixed
|
||||
{
|
||||
return ['id' => $this->id];
|
||||
}
|
||||
}
|
||||
|
|
@ -109,6 +109,8 @@ abstract class RequestAbstract implements MessageInterface
|
|||
return (float) $this->data[$key];
|
||||
case 'bool':
|
||||
return (bool) $this->data[$key];
|
||||
case 'DateTime':
|
||||
return new \DateTime($this->data[$key]);
|
||||
default:
|
||||
return $this->data[$key];
|
||||
}
|
||||
|
|
|
|||
55
Security/Guard.php
Normal file
55
Security/Guard.php
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
<?php
|
||||
/**
|
||||
* Karaka
|
||||
*
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Security
|
||||
* @copyright Dennis Eichhorn
|
||||
* @license OMS License 1.0
|
||||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace phpOMS\Security;
|
||||
|
||||
use phpOMS\System\File\FileUtils;
|
||||
|
||||
/**
|
||||
* Php code security class.
|
||||
*
|
||||
* This can be used to guard against certain vulnerabilities
|
||||
*
|
||||
* @package phpOMS\Security
|
||||
* @license OMS License 1.0
|
||||
* @link https://jingga.app
|
||||
* @since 1.0.0
|
||||
*/
|
||||
final class Guard
|
||||
{
|
||||
/**
|
||||
* Base path for the application
|
||||
*
|
||||
* @var string
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public static string $BASE_PATH = __DIR__ . '/../../';
|
||||
|
||||
/**
|
||||
* Make sure a path is part of a base path
|
||||
*
|
||||
* This can be used to verify if a path goes outside of the allowed path bounds
|
||||
*
|
||||
* @param string $path Path to check
|
||||
* @param string $base Base path
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public static function isSafePath(string $path, string $base = '') : bool
|
||||
{
|
||||
return \stripos(FileUtils::absolute($path), FileUtils::absolute(empty($base) ? self::$BASE_PATH : $base)) === 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -39,7 +39,7 @@ final class PhpCode
|
|||
'ftp_rawlist', 'highlight_file', 'ini_alter', 'ini_get_all', 'ini_restore', 'inject_code', 'mysql_pconnect',
|
||||
'openlog', 'php_uname', 'phpAds_remoteInfo', 'phpAds_XmlRpc', 'phpAds_xmlrpcDecode',
|
||||
'phpAds_xmlrpcEncode', 'popen', 'posix_getpwuid', 'posix_kill', 'posix_mkfifo', 'posix_setpgid', 'posix_setsid',
|
||||
'posix_setuid', 'posix_uname', 'proc_close', 'proc_get_status', 'shell_exec',
|
||||
'posix_setuid', 'posix_uname', 'proc_close', 'proc_get_status', 'shell_exec', 'serialize', 'unserialize', '__serialize', '__unserialize',
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -290,22 +290,31 @@ final class Directory extends FileAbstract implements DirectoryInterface
|
|||
return false;
|
||||
}
|
||||
|
||||
$files = \scandir($path);
|
||||
$counter = 0;
|
||||
$files = \scandir($path);
|
||||
|
||||
if ($files === false) {
|
||||
return false; // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
/* Removing . and .. */
|
||||
unset($files[1]);
|
||||
unset($files[0]);
|
||||
|
||||
foreach ($files as $file) {
|
||||
if (\is_dir($path . '/' . $file)) {
|
||||
self::delete($path . '/' . $file);
|
||||
} else {
|
||||
\unlink($path . '/' . $file);
|
||||
do {
|
||||
if ($files === false) {
|
||||
return false; // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
foreach ($files as $file) {
|
||||
if ($file === '.' || $file === '..') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (\is_dir($path . '/' . $file)) {
|
||||
self::delete($path . '/' . $file);
|
||||
} else {
|
||||
\unlink($path . '/' . $file);
|
||||
}
|
||||
}
|
||||
|
||||
++$counter;
|
||||
} while ($counter < 3 && \count($files = \scandir($path)) > 2);
|
||||
|
||||
if (\count(\scandir($path)) > 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
\rmdir($path);
|
||||
|
|
|
|||
|
|
@ -112,10 +112,16 @@ final class ImageUtils
|
|||
*/
|
||||
public static function resize(string $srcPath, string $dstPath, int $width, int $height, bool $crop = false) : void
|
||||
{
|
||||
if (!\is_file($srcPath)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/** @var array $imageDim */
|
||||
$imageDim = \getimagesize($srcPath);
|
||||
|
||||
if (($imageDim[0] ?? -1) >= $width && ($imageDim[1] ?? -1) >= $height) {
|
||||
if ((($imageDim[0] ?? -1) >= $width && ($imageDim[1] ?? -1) >= $height)
|
||||
|| ($imageDim[0] === 0 || $imageDim[1] === 0)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -158,5 +164,133 @@ final class ImageUtils
|
|||
} elseif (\stripos($srcPath, '.gif')) {
|
||||
\imagegif($dst, $dstPath);
|
||||
}
|
||||
|
||||
\imagedestroy($src);
|
||||
\imagedestroy($dst);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get difference between two images
|
||||
*
|
||||
* @param string $img1 Path to first image
|
||||
* @param string $img2 Path to second image
|
||||
* @param string $out Output path for difference image (empty = no difference image is created)
|
||||
* @param int $diff Difference image type (0 = only show differences of img2, 1 = make differences red/green colored)
|
||||
*
|
||||
* @return int Amount of pixel differences
|
||||
*
|
||||
*/
|
||||
public static function difference(string $img1, string $img2, string $out = '', int $diff = 0) : int
|
||||
{
|
||||
$src1 = null;
|
||||
if (\stripos($img1, '.jpg') !== false || \stripos($img1, '.jpeg') !== false) {
|
||||
$src1 = \imagecreatefromjpeg($img1);
|
||||
} elseif (\stripos($img1, '.png') !== false) {
|
||||
$src1 = \imagecreatefrompng($img1);
|
||||
} elseif (\stripos($img1, '.gif') !== false) {
|
||||
$src1 = \imagecreatefromgif($img1);
|
||||
}
|
||||
|
||||
$src2 = null;
|
||||
if (\stripos($img2, '.jpg') !== false || \stripos($img2, '.jpeg') !== false) {
|
||||
$src2 = \imagecreatefromjpeg($img2);
|
||||
} elseif (\stripos($img2, '.png') !== false) {
|
||||
$src2 = \imagecreatefrompng($img2);
|
||||
} elseif (\stripos($img2, '.gif') !== false) {
|
||||
$src2 = \imagecreatefromgif($img2);
|
||||
}
|
||||
|
||||
if ($src1 === null || $src2 === null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$imageDim1 = [\imagesx($src1), \imagesy($src1)];
|
||||
$imageDim2 = [\imagesx($src2), \imagesy($src2)];
|
||||
|
||||
$newDim = [\max($imageDim1[0], $imageDim2[0]), \max($imageDim1[1], $imageDim2[1])];
|
||||
|
||||
$diff = empty($out) ? -1 : $out;
|
||||
|
||||
if ($diff !== -1) {
|
||||
$dst = $diff === 0
|
||||
? \imagecreatetruecolor($newDim[0], $newDim[1])
|
||||
: \imagecrop($src2, ['x' => 0, 'y' => 0, 'width' => $imageDim2[0], 'height' => $imageDim2[1]]);
|
||||
|
||||
$alpha = \imagecolorallocatealpha($dst, 255, 255, 255, 127);
|
||||
if ($diff === 0) {
|
||||
\imagefill($dst, 0, 0, $alpha);
|
||||
}
|
||||
|
||||
$red = \imagecolorallocate($dst, 255, 0, 0);
|
||||
$green = \imagecolorallocate($dst, 0, 255, 0);
|
||||
}
|
||||
|
||||
$difference = 0;
|
||||
|
||||
for ($i = 0; $i < $newDim[0]; ++$i) {
|
||||
for ($j = 0; $j < $newDim[1]; ++$j) {
|
||||
if ($i >= $imageDim1[0] || $j >= $imageDim1[1]) {
|
||||
if ($diff === 0) {
|
||||
\imagesetpixel($dst, $i, $j, $green);
|
||||
} elseif ($diff === 1) {
|
||||
if ($i >= $imageDim2[0] || $j >= $imageDim2[1]) {
|
||||
\imagesetpixel($dst, $i, $j, $green);
|
||||
} else {
|
||||
$color2 = \imagecolerat($src2, $i, $j);
|
||||
\imagesetpixel($dst, $i, $j, $color2);
|
||||
}
|
||||
}
|
||||
|
||||
++$difference;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($i >= $imageDim2[0] || $j >= $imageDim2[1]) {
|
||||
if ($diff === 0) {
|
||||
\imagesetpixel($dst, $i, $j, $red);
|
||||
} elseif ($diff === 1) {
|
||||
if ($i >= $imageDim1[0] || $j >= $imageDim1[1]) {
|
||||
\imagesetpixel($dst, $i, $j, $red);
|
||||
} else {
|
||||
$color1 = \imagecolerat($src1, $i, $j);
|
||||
\imagesetpixel($dst, $i, $j, $color1);
|
||||
}
|
||||
}
|
||||
|
||||
++$difference;
|
||||
continue;
|
||||
}
|
||||
|
||||
$color1 = \imagecolerat($src1, $i, $j);
|
||||
$color2 = \imagecolerat($src2, $i, $j);
|
||||
|
||||
if ($color1 !== $color2) {
|
||||
++$difference;
|
||||
|
||||
if ($diff === 0) {
|
||||
\imagesetpixel($dst, $i, $j, $color2);
|
||||
} elseif ($diff === 1) {
|
||||
\imagesetpixel($dst, $i, $j, $green);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($diff !== -1) {
|
||||
if (\stripos($out, '.jpg') || \stripos($out, '.jpeg')) {
|
||||
\imagejpeg($dst, $out);
|
||||
} elseif (\stripos($out, '.png')) {
|
||||
\imagesavealpha($dst, true);
|
||||
\imagepng($dst, $out);
|
||||
} elseif (\stripos($out, '.gif')) {
|
||||
\imagegif($dst, $out);
|
||||
}
|
||||
|
||||
\imagedestroy($src1);
|
||||
\imagedestroy($src2);
|
||||
\imagedestroy($dest);
|
||||
}
|
||||
|
||||
return $difference;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
57
Utils/Parser/Document/DocumentParser.php
Normal file
57
Utils/Parser/Document/DocumentParser.php
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
<?php
|
||||
/**
|
||||
* Karaka
|
||||
*
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Utils\Parser\Document
|
||||
* @copyright Dennis Eichhorn
|
||||
* @license OMS License 1.0
|
||||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace phpOMS\Utils\Parser\Document;
|
||||
|
||||
use PhpOffice\PhpWord\IOFactory;
|
||||
use PhpOffice\PhpWord\Writer\HTML;
|
||||
|
||||
/**
|
||||
* Presentation parser class.
|
||||
*
|
||||
* @package phpOMS\Utils\Parser\Document
|
||||
* @license OMS License 1.0
|
||||
* @link https://jingga.app
|
||||
* @since 1.0.0
|
||||
*/
|
||||
class DocumentParser
|
||||
{
|
||||
/**
|
||||
* Document to string
|
||||
*
|
||||
* @param string $path Path
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public static function parseDocument(string $path, string $output = 'html') : string
|
||||
{
|
||||
if ($output === 'html') {
|
||||
$doc = IOFactory::load($path);
|
||||
|
||||
$writer = new HTML($doc);
|
||||
|
||||
return $writer->getContent();
|
||||
} elseif ($output === 'pdf') {
|
||||
$doc = IOFactory::load($path);
|
||||
|
||||
$writer = new DocumentWriter($doc);
|
||||
|
||||
return $writer->toPdfString();
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
}
|
||||
53
Utils/Parser/Document/DocumentWriter.php
Normal file
53
Utils/Parser/Document/DocumentWriter.php
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
<?php
|
||||
/**
|
||||
* Karaka
|
||||
*
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Utils\Parser\Document
|
||||
* @copyright Dennis Eichhorn
|
||||
* @license OMS License 1.0
|
||||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace phpOMS\Utils\Parser\Document;
|
||||
|
||||
use PhpOffice\PhpWord\PhpWord;
|
||||
use PhpOffice\PhpWord\Settings;
|
||||
use PhpOffice\PhpWord\Writer\WriterInterface;
|
||||
|
||||
class DocumentWriter extends AbstractRenderer implements WriterInterface
|
||||
{
|
||||
/**
|
||||
* Save PhpWord to file.
|
||||
*
|
||||
* @param string $filename Name of the file to save as
|
||||
*/
|
||||
public function toPdfString($filename = null): void
|
||||
{
|
||||
// PDF settings
|
||||
$paperSize = strtoupper('A4');
|
||||
$orientation = strtoupper('portrait');
|
||||
|
||||
// Create PDF
|
||||
$pdf = $pdf = new \Mpdf\Mpdf();
|
||||
$pdf->_setPageSize($paperSize, $orientation);
|
||||
$pdf->addPage($orientation);
|
||||
|
||||
// Write document properties
|
||||
$phpWord = $this->getPhpWord();
|
||||
$docProps = $phpWord->getDocInfo();
|
||||
$pdf->setTitle($docProps->getTitle());
|
||||
$pdf->setAuthor($docProps->getCreator());
|
||||
$pdf->setSubject($docProps->getSubject());
|
||||
$pdf->setKeywords($docProps->getKeywords());
|
||||
$pdf->setCreator($docProps->getCreator());
|
||||
|
||||
$pdf->writeHTML($this->getContent());
|
||||
|
||||
// Write to file
|
||||
return $pdf->output($filename, 'S');
|
||||
}
|
||||
}
|
||||
52
Utils/Parser/Presentation/PresentationParser.php
Normal file
52
Utils/Parser/Presentation/PresentationParser.php
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
<?php
|
||||
/**
|
||||
* Karaka
|
||||
*
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Utils\Parser\Presentation
|
||||
* @copyright Dennis Eichhorn
|
||||
* @license OMS License 1.0
|
||||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace phpOMS\Utils\Parser\Presentation;
|
||||
|
||||
use PhpOffice\PhpPresentation\IOFactory;
|
||||
|
||||
/**
|
||||
* Presentation parser class.
|
||||
*
|
||||
* @package phpOMS\Utils\Parser\Presentation
|
||||
* @license OMS License 1.0
|
||||
* @link https://jingga.app
|
||||
* @since 1.0.0
|
||||
*/
|
||||
class PresentationParser
|
||||
{
|
||||
/**
|
||||
* Presentation to string
|
||||
*
|
||||
* @param string $path Path
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public static function parsePresentation(string $path, string $output = 'html') : string
|
||||
{
|
||||
if ($output === 'html') {
|
||||
// $pptReader = IOFactory::createReader('PowerPoint2007');
|
||||
// $pptReader->load(...);
|
||||
$presentation = IOFactory::load($path);
|
||||
|
||||
$oTree = new PresentationWriter($presentation);
|
||||
|
||||
return $oTree->renderHtml();
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
}
|
||||
317
Utils/Parser/Presentation/PresentationWriter.php
Normal file
317
Utils/Parser/Presentation/PresentationWriter.php
Normal file
|
|
@ -0,0 +1,317 @@
|
|||
<?php
|
||||
/**
|
||||
* Karaka
|
||||
*
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Utils\Parser\Presentation
|
||||
* @copyright Dennis Eichhorn
|
||||
* @license OMS License 1.0
|
||||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace phpOMS\Utils\Parser\Presentation;
|
||||
|
||||
use PhpOffice\PhpPresentation\AbstractShape;
|
||||
use PhpOffice\PhpPresentation\Autoloader;
|
||||
use PhpOffice\PhpPresentation\DocumentLayout;
|
||||
use PhpOffice\PhpPresentation\IOFactory;
|
||||
use PhpOffice\PhpPresentation\PhpPresentation;
|
||||
use PhpOffice\PhpPresentation\Shape\Drawing;
|
||||
use PhpOffice\PhpPresentation\Shape\Group;
|
||||
use PhpOffice\PhpPresentation\Shape\RichText;
|
||||
use PhpOffice\PhpPresentation\Shape\RichText\BreakElement;
|
||||
use PhpOffice\PhpPresentation\Shape\RichText\TextElement;
|
||||
use PhpOffice\PhpPresentation\Slide;
|
||||
use PhpOffice\PhpPresentation\Style\Alignment;
|
||||
use PhpOffice\PhpPresentation\Style\Bullet;
|
||||
use PhpOffice\PhpPresentation\Style\Color;
|
||||
|
||||
/**
|
||||
* Presentation parser class.
|
||||
*
|
||||
* @package phpOMS\Utils\Parser\Presentation
|
||||
* @license OMS License 1.0
|
||||
* @link https://jingga.app
|
||||
* @since 1.0.0
|
||||
*/
|
||||
class PresentationWriter
|
||||
{
|
||||
protected $oPhpPresentation;
|
||||
protected $htmlOutput;
|
||||
|
||||
public function __construct(PhpPresentation $oPHPPpt)
|
||||
{
|
||||
$this->oPhpPresentation = $oPHPPpt;
|
||||
}
|
||||
|
||||
public function renderHtml()
|
||||
{
|
||||
$this->append('<div class="container-fluid pptTree">');
|
||||
$this->append('<div class="row">');
|
||||
$this->append('<div class="collapse in col-md-6">');
|
||||
$this->append('<div class="tree">');
|
||||
$this->append('<ul>');
|
||||
$this->displayPhpPresentation($this->oPhpPresentation);
|
||||
$this->append('</ul>');
|
||||
$this->append('</div>');
|
||||
$this->append('</div>');
|
||||
$this->append('<div class="col-md-6">');
|
||||
$this->displayPhpPresentationInfo($this->oPhpPresentation);
|
||||
$this->append('</div>');
|
||||
$this->append('</div>');
|
||||
$this->append('</div>');
|
||||
|
||||
return $this->htmlOutput;
|
||||
}
|
||||
|
||||
protected function append($sHTML)
|
||||
{
|
||||
$this->htmlOutput .= $sHTML;
|
||||
}
|
||||
|
||||
protected function displayPhpPresentation(PhpPresentation $oPHPPpt)
|
||||
{
|
||||
$this->append('<li><span><i class="fa fa-folder-open"></i> PhpPresentation</span>');
|
||||
$this->append('<ul>');
|
||||
$this->append('<li><span class="shape" id="divPhpPresentation"><i class="fa fa-info-circle"></i> Info "PhpPresentation"</span></li>');
|
||||
foreach ($oPHPPpt->getAllSlides() as $oSlide) {
|
||||
$this->append('<li><span><i class="fa fa-minus-square"></i> Slide</span>');
|
||||
$this->append('<ul>');
|
||||
$this->append('<li><span class="shape" id="div' . $oSlide->getHashCode() . '"><i class="fa fa-info-circle"></i> Info "Slide"</span></li>');
|
||||
foreach ($oSlide->getShapeCollection() as $oShape) {
|
||||
if ($oShape instanceof Group) {
|
||||
$this->append('<li><span><i class="fa fa-minus-square"></i> Shape "Group"</span>');
|
||||
$this->append('<ul>');
|
||||
// $this->append('<li><span class="shape" id="div'.$oShape->getHashCode().'"><i class="fa fa-info-circle"></i> Info "Group"</span></li>');
|
||||
foreach ($oShape->getShapeCollection() as $oShapeChild) {
|
||||
$this->displayShape($oShapeChild);
|
||||
}
|
||||
$this->append('</ul>');
|
||||
$this->append('</li>');
|
||||
} else {
|
||||
$this->displayShape($oShape);
|
||||
}
|
||||
}
|
||||
$this->append('</ul>');
|
||||
$this->append('</li>');
|
||||
}
|
||||
$this->append('</ul>');
|
||||
$this->append('</li>');
|
||||
}
|
||||
|
||||
protected function displayShape(AbstractShape $shape)
|
||||
{
|
||||
if ($shape instanceof Drawing\Gd) {
|
||||
$this->append('<li><span class="shape" id="div' . $shape->getHashCode() . '">Shape "Drawing\Gd"</span></li>');
|
||||
} elseif ($shape instanceof Drawing\File) {
|
||||
$this->append('<li><span class="shape" id="div' . $shape->getHashCode() . '">Shape "Drawing\File"</span></li>');
|
||||
} elseif ($shape instanceof Drawing\Base64) {
|
||||
$this->append('<li><span class="shape" id="div' . $shape->getHashCode() . '">Shape "Drawing\Base64"</span></li>');
|
||||
} elseif ($shape instanceof Drawing\ZipFile) {
|
||||
$this->append('<li><span class="shape" id="div' . $shape->getHashCode() . '">Shape "Drawing\Zip"</span></li>');
|
||||
} elseif ($shape instanceof RichText) {
|
||||
$this->append('<li><span class="shape" id="div' . $shape->getHashCode() . '">Shape "RichText"</span></li>');
|
||||
} else {
|
||||
var_dump($shape);
|
||||
}
|
||||
}
|
||||
|
||||
protected function displayPhpPresentationInfo(PhpPresentation $oPHPPpt)
|
||||
{
|
||||
$this->append('<div class="infoBlk" id="divPhpPresentationInfo">');
|
||||
$this->append('<dl>');
|
||||
$this->append('<dt>Number of slides</dt><dd>' . $oPHPPpt->getSlideCount() . '</dd>');
|
||||
$this->append('<dt>Document Layout Name</dt><dd>' . (empty($oPHPPpt->getLayout()->getDocumentLayout()) ? 'Custom' : $oPHPPpt->getLayout()->getDocumentLayout()) . '</dd>');
|
||||
$this->append('<dt>Document Layout Height</dt><dd>' . $oPHPPpt->getLayout()->getCY(DocumentLayout::UNIT_MILLIMETER) . ' mm</dd>');
|
||||
$this->append('<dt>Document Layout Width</dt><dd>' . $oPHPPpt->getLayout()->getCX(DocumentLayout::UNIT_MILLIMETER) . ' mm</dd>');
|
||||
$this->append('<dt>Properties : Category</dt><dd>' . $oPHPPpt->getDocumentProperties()->getCategory() . '</dd>');
|
||||
$this->append('<dt>Properties : Company</dt><dd>' . $oPHPPpt->getDocumentProperties()->getCompany() . '</dd>');
|
||||
$this->append('<dt>Properties : Created</dt><dd>' . $oPHPPpt->getDocumentProperties()->getCreated() . '</dd>');
|
||||
$this->append('<dt>Properties : Creator</dt><dd>' . $oPHPPpt->getDocumentProperties()->getCreator() . '</dd>');
|
||||
$this->append('<dt>Properties : Description</dt><dd>' . $oPHPPpt->getDocumentProperties()->getDescription() . '</dd>');
|
||||
$this->append('<dt>Properties : Keywords</dt><dd>' . $oPHPPpt->getDocumentProperties()->getKeywords() . '</dd>');
|
||||
$this->append('<dt>Properties : Last Modified By</dt><dd>' . $oPHPPpt->getDocumentProperties()->getLastModifiedBy() . '</dd>');
|
||||
$this->append('<dt>Properties : Modified</dt><dd>' . $oPHPPpt->getDocumentProperties()->getModified() . '</dd>');
|
||||
$this->append('<dt>Properties : Subject</dt><dd>' . $oPHPPpt->getDocumentProperties()->getSubject() . '</dd>');
|
||||
$this->append('<dt>Properties : Title</dt><dd>' . $oPHPPpt->getDocumentProperties()->getTitle() . '</dd>');
|
||||
$this->append('</dl>');
|
||||
$this->append('</div>');
|
||||
|
||||
foreach ($oPHPPpt->getAllSlides() as $oSlide) {
|
||||
$this->append('<div class="infoBlk" id="div' . $oSlide->getHashCode() . 'Info">');
|
||||
$this->append('<dl>');
|
||||
$this->append('<dt>HashCode</dt><dd>' . $oSlide->getHashCode() . '</dd>');
|
||||
$this->append('<dt>Slide Layout</dt><dd>Layout::' . $this->getConstantName('\PhpOffice\PhpPresentation\Slide\Layout', $oSlide->getSlideLayout()) . '</dd>');
|
||||
|
||||
$this->append('<dt>Offset X</dt><dd>' . $oSlide->getOffsetX() . '</dd>');
|
||||
$this->append('<dt>Offset Y</dt><dd>' . $oSlide->getOffsetY() . '</dd>');
|
||||
$this->append('<dt>Extent X</dt><dd>' . $oSlide->getExtentX() . '</dd>');
|
||||
$this->append('<dt>Extent Y</dt><dd>' . $oSlide->getExtentY() . '</dd>');
|
||||
$oBkg = $oSlide->getBackground();
|
||||
if ($oBkg instanceof Slide\AbstractBackground) {
|
||||
if ($oBkg instanceof Slide\Background\Color) {
|
||||
$this->append('<dt>Background Color</dt><dd>#' . $oBkg->getColor()->getRGB() . '</dd>');
|
||||
}
|
||||
if ($oBkg instanceof Slide\Background\Image) {
|
||||
$sBkgImgContents = file_get_contents($oBkg->getPath());
|
||||
$this->append('<dt>Background Image</dt><dd><img src="data:image/png;base64,' . base64_encode($sBkgImgContents) . '"></dd>');
|
||||
}
|
||||
}
|
||||
$oNote = $oSlide->getNote();
|
||||
if ($oNote->getShapeCollection()->count() > 0) {
|
||||
$this->append('<dt>Notes</dt>');
|
||||
foreach ($oNote->getShapeCollection() as $oShape) {
|
||||
if ($oShape instanceof RichText) {
|
||||
$this->append('<dd>' . $oShape->getPlainText() . '</dd>');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->append('</dl>');
|
||||
$this->append('</div>');
|
||||
|
||||
foreach ($oSlide->getShapeCollection() as $oShape) {
|
||||
if ($oShape instanceof Group) {
|
||||
foreach ($oShape->getShapeCollection() as $oShapeChild) {
|
||||
$this->displayShapeInfo($oShapeChild);
|
||||
}
|
||||
} else {
|
||||
$this->displayShapeInfo($oShape);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function displayShapeInfo(AbstractShape $oShape)
|
||||
{
|
||||
$this->append('<div class="infoBlk" id="div' . $oShape->getHashCode() . 'Info">');
|
||||
$this->append('<dl>');
|
||||
$this->append('<dt>HashCode</dt><dd>' . $oShape->getHashCode() . '</dd>');
|
||||
$this->append('<dt>Offset X</dt><dd>' . $oShape->getOffsetX() . '</dd>');
|
||||
$this->append('<dt>Offset Y</dt><dd>' . $oShape->getOffsetY() . '</dd>');
|
||||
$this->append('<dt>Height</dt><dd>' . $oShape->getHeight() . '</dd>');
|
||||
$this->append('<dt>Width</dt><dd>' . $oShape->getWidth() . '</dd>');
|
||||
$this->append('<dt>Rotation</dt><dd>' . $oShape->getRotation() . '°</dd>');
|
||||
$this->append('<dt>Hyperlink</dt><dd>' . ucfirst(var_export($oShape->hasHyperlink(), true)) . '</dd>');
|
||||
$this->append('<dt>Fill</dt>');
|
||||
if (is_null($oShape->getFill())) {
|
||||
$this->append('<dd>None</dd>');
|
||||
} else {
|
||||
switch ($oShape->getFill()->getFillType()) {
|
||||
case \PhpOffice\PhpPresentation\Style\Fill::FILL_NONE:
|
||||
$this->append('<dd>None</dd>');
|
||||
break;
|
||||
case \PhpOffice\PhpPresentation\Style\Fill::FILL_SOLID:
|
||||
$this->append('<dd>Solid (');
|
||||
$this->append('Color : #' . $oShape->getFill()->getStartColor()->getRGB());
|
||||
$this->append(' - Alpha : ' . $oShape->getFill()->getStartColor()->getAlpha() . '%');
|
||||
$this->append(')</dd>');
|
||||
break;
|
||||
}
|
||||
}
|
||||
$this->append('<dt>Border</dt><dd>@Todo</dd>');
|
||||
$this->append('<dt>IsPlaceholder</dt><dd>' . ($oShape->isPlaceholder() ? 'true' : 'false') . '</dd>');
|
||||
if ($oShape instanceof Drawing\Gd) {
|
||||
$this->append('<dt>Name</dt><dd>' . $oShape->getName() . '</dd>');
|
||||
$this->append('<dt>Description</dt><dd>' . $oShape->getDescription() . '</dd>');
|
||||
ob_start();
|
||||
call_user_func($oShape->getRenderingFunction(), $oShape->getImageResource());
|
||||
$sShapeImgContents = ob_get_contents();
|
||||
ob_end_clean();
|
||||
$this->append('<dt>Mime-Type</dt><dd>' . $oShape->getMimeType() . '</dd>');
|
||||
$this->append('<dt>Image</dt><dd><img src="data:' . $oShape->getMimeType() . ';base64,' . base64_encode($sShapeImgContents) . '"></dd>');
|
||||
if ($oShape->hasHyperlink()) {
|
||||
$this->append('<dt>Hyperlink URL</dt><dd>' . $oShape->getHyperlink()->getUrl() . '</dd>');
|
||||
$this->append('<dt>Hyperlink Tooltip</dt><dd>' . $oShape->getHyperlink()->getTooltip() . '</dd>');
|
||||
}
|
||||
} elseif ($oShape instanceof Drawing\AbstractDrawingAdapter) {
|
||||
$this->append('<dt>Name</dt><dd>' . $oShape->getName() . '</dd>');
|
||||
$this->append('<dt>Description</dt><dd>' . $oShape->getDescription() . '</dd>');
|
||||
} elseif ($oShape instanceof RichText) {
|
||||
$this->append('<dt># of paragraphs</dt><dd>' . count($oShape->getParagraphs()) . '</dd>');
|
||||
$this->append('<dt>Inset (T / R / B / L)</dt><dd>' . $oShape->getInsetTop() . 'px / ' . $oShape->getInsetRight() . 'px / ' . $oShape->getInsetBottom() . 'px / ' . $oShape->getInsetLeft() . 'px</dd>');
|
||||
$this->append('<dt>Text</dt>');
|
||||
$this->append('<dd>');
|
||||
foreach ($oShape->getParagraphs() as $oParagraph) {
|
||||
$this->append('Paragraph<dl>');
|
||||
$this->append('<dt>Alignment Horizontal</dt><dd> Alignment::' . $this->getConstantName('\PhpOffice\PhpPresentation\Style\Alignment', $oParagraph->getAlignment()->getHorizontal()) . '</dd>');
|
||||
$this->append('<dt>Alignment Vertical</dt><dd> Alignment::' . $this->getConstantName('\PhpOffice\PhpPresentation\Style\Alignment', $oParagraph->getAlignment()->getVertical()) . '</dd>');
|
||||
$this->append('<dt>Alignment Margin (L / R)</dt><dd>' . $oParagraph->getAlignment()->getMarginLeft() . ' px / ' . $oParagraph->getAlignment()->getMarginRight() . 'px</dd>');
|
||||
$this->append('<dt>Alignment Indent</dt><dd>' . $oParagraph->getAlignment()->getIndent() . ' px</dd>');
|
||||
$this->append('<dt>Alignment Level</dt><dd>' . $oParagraph->getAlignment()->getLevel() . '</dd>');
|
||||
$this->append('<dt>Bullet Style</dt><dd> Bullet::' . $this->getConstantName('\PhpOffice\PhpPresentation\Style\Bullet', $oParagraph->getBulletStyle()->getBulletType()) . '</dd>');
|
||||
if (Bullet::TYPE_NONE != $oParagraph->getBulletStyle()->getBulletType()) {
|
||||
$this->append('<dt>Bullet Font</dt><dd>' . $oParagraph->getBulletStyle()->getBulletFont() . '</dd>');
|
||||
$this->append('<dt>Bullet Color</dt><dd>' . $oParagraph->getBulletStyle()->getBulletColor()->getARGB() . '</dd>');
|
||||
}
|
||||
if (Bullet::TYPE_BULLET == $oParagraph->getBulletStyle()->getBulletType()) {
|
||||
$this->append('<dt>Bullet Char</dt><dd>' . $oParagraph->getBulletStyle()->getBulletChar() . '</dd>');
|
||||
}
|
||||
if (Bullet::TYPE_NUMERIC == $oParagraph->getBulletStyle()->getBulletType()) {
|
||||
$this->append('<dt>Bullet Start At</dt><dd>' . $oParagraph->getBulletStyle()->getBulletNumericStartAt() . '</dd>');
|
||||
$this->append('<dt>Bullet Style</dt><dd>' . $oParagraph->getBulletStyle()->getBulletNumericStyle() . '</dd>');
|
||||
}
|
||||
$this->append('<dt>Line Spacing</dt><dd>' . $oParagraph->getLineSpacing() . '</dd>');
|
||||
$this->append('<dt>RichText</dt><dd><dl>');
|
||||
foreach ($oParagraph->getRichTextElements() as $oRichText) {
|
||||
if ($oRichText instanceof BreakElement) {
|
||||
$this->append('<dt><i>Break</i></dt>');
|
||||
} else {
|
||||
if ($oRichText instanceof TextElement) {
|
||||
$this->append('<dt><i>TextElement</i></dt>');
|
||||
} else {
|
||||
$this->append('<dt><i>Run</i></dt>');
|
||||
}
|
||||
$this->append('<dd>' . $oRichText->getText());
|
||||
$this->append('<dl>');
|
||||
$this->append('<dt>Font Name</dt><dd>' . $oRichText->getFont()->getName() . '</dd>');
|
||||
$this->append('<dt>Font Size</dt><dd>' . $oRichText->getFont()->getSize() . '</dd>');
|
||||
$this->append('<dt>Font Color</dt><dd>#' . $oRichText->getFont()->getColor()->getARGB() . '</dd>');
|
||||
$this->append('<dt>Font Transform</dt><dd>');
|
||||
$this->append('<abbr title="Bold">Bold</abbr> : ' . ($oRichText->getFont()->isBold() ? 'Y' : 'N') . ' - ');
|
||||
$this->append('<abbr title="Italic">Italic</abbr> : ' . ($oRichText->getFont()->isItalic() ? 'Y' : 'N') . ' - ');
|
||||
$this->append('<abbr title="Underline">Underline</abbr> : Underline::' . $this->getConstantName('\PhpOffice\PhpPresentation\Style\Font', $oRichText->getFont()->getUnderline()) . ' - ');
|
||||
$this->append('<abbr title="Strikethrough">Strikethrough</abbr> : ' . ($oRichText->getFont()->isStrikethrough() ? 'Y' : 'N') . ' - ');
|
||||
$this->append('<abbr title="SubScript">SubScript</abbr> : ' . ($oRichText->getFont()->isSubScript() ? 'Y' : 'N') . ' - ');
|
||||
$this->append('<abbr title="SuperScript">SuperScript</abbr> : ' . ($oRichText->getFont()->isSuperScript() ? 'Y' : 'N'));
|
||||
$this->append('</dd>');
|
||||
if ($oRichText instanceof TextElement) {
|
||||
if ($oRichText->hasHyperlink()) {
|
||||
$this->append('<dt>Hyperlink URL</dt><dd>' . $oRichText->getHyperlink()->getUrl() . '</dd>');
|
||||
$this->append('<dt>Hyperlink Tooltip</dt><dd>' . $oRichText->getHyperlink()->getTooltip() . '</dd>');
|
||||
}
|
||||
}
|
||||
$this->append('</dl>');
|
||||
$this->append('</dd>');
|
||||
}
|
||||
}
|
||||
$this->append('</dl></dd></dl>');
|
||||
}
|
||||
$this->append('</dd>');
|
||||
} else {
|
||||
// Add another shape
|
||||
}
|
||||
$this->append('</dl>');
|
||||
$this->append('</div>');
|
||||
}
|
||||
|
||||
protected function getConstantName($class, $search, $startWith = '')
|
||||
{
|
||||
$fooClass = new \ReflectionClass($class);
|
||||
$constants = $fooClass->getConstants();
|
||||
$constName = null;
|
||||
foreach ($constants as $key => $value) {
|
||||
if ($value == $search) {
|
||||
if (empty($startWith) || (!empty($startWith) && 0 === strpos($key, $startWith))) {
|
||||
$constName = $key;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $constName;
|
||||
}
|
||||
}
|
||||
71
Utils/Parser/Spreadsheet/SpreadsheetParser.php
Normal file
71
Utils/Parser/Spreadsheet/SpreadsheetParser.php
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
<?php
|
||||
/**
|
||||
* Karaka
|
||||
*
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Utils\Parser\Spreadsheet
|
||||
* @copyright Dennis Eichhorn
|
||||
* @license OMS License 1.0
|
||||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace phpOMS\Utils\Parser\Spreadsheet;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\IOFactory;
|
||||
use PhpOffice\PhpSpreadsheet\Worksheet\PageSetup;
|
||||
|
||||
/**
|
||||
* Spreadsheet parser class.
|
||||
*
|
||||
* @package phpOMS\Utils\Parser\Spreadsheet
|
||||
* @license OMS License 1.0
|
||||
* @link https://jingga.app
|
||||
* @since 1.0.0
|
||||
*/
|
||||
class SpreadsheetParser
|
||||
{
|
||||
/**
|
||||
* Spreadsheet to string
|
||||
*
|
||||
* @param string $path Path
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public static function parseSpreadsheet(string $path, string $output = 'json') : string
|
||||
{
|
||||
if ($output === 'json') {
|
||||
$spreadsheet = IOFactory::load($path);
|
||||
|
||||
$sheetCount = $spreadsheet->getSheetCount();
|
||||
for ($i = 0; $i < $sheetCount; ++$i) {
|
||||
$csv[] = $spreadsheet->getSheet($i)->toArray(null, true, true, true);
|
||||
}
|
||||
|
||||
return \json_encode($csv);
|
||||
} elseif ($output === 'pdf') {
|
||||
$spreadsheet = IOFactory::load($path);
|
||||
|
||||
$spreadsheet->getActiveSheet()->setShowGridLines(false);
|
||||
$spreadsheet->getActiveSheet()->getPageSetup()->setOrientation(PageSetup::ORIENTATION_LANDSCAPE);
|
||||
|
||||
IOFactory::registerWriter('custom', \phpOMS\Utils\Parser\Spreadsheet\SpreadsheetWriter::class);
|
||||
$writer = IOFactory::createWriter($spreadsheet, 'custom');
|
||||
|
||||
return $writer->toPdfString();
|
||||
} elseif ($output === 'html') {
|
||||
$spreadsheet = IOFactory::load($path);
|
||||
|
||||
IOFactory::registerWriter('custom', \phpOMS\Utils\Parser\Spreadsheet\SpreadsheetWriter::class);
|
||||
$writer = IOFactory::createWriter($spreadsheet, 'custom');
|
||||
|
||||
return $writer->generateHtmlAll();
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
}
|
||||
91
Utils/Parser/Spreadsheet/SpreadsheetWriter.php
Normal file
91
Utils/Parser/Spreadsheet/SpreadsheetWriter.php
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
<?php
|
||||
/**
|
||||
* Karaka
|
||||
*
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Utils\Parser\Spreadsheet
|
||||
* @copyright Dennis Eichhorn
|
||||
* @license OMS License 1.0
|
||||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace phpOMS\Utils\Parser\Spreadsheet;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Worksheet\PageSetup;
|
||||
use PhpOffice\PhpSpreadsheet\Writer\Html;
|
||||
use PhpOffice\PhpSpreadsheet\Writer\Pdf;
|
||||
|
||||
class SpreadsheetWriter extends Pdf
|
||||
{
|
||||
/** @var bool */
|
||||
protected $isMPdf = true;
|
||||
|
||||
/**
|
||||
* Save Spreadsheet to file.
|
||||
*
|
||||
* @param string $filename Name of the file to save as
|
||||
*/
|
||||
public function toPdfString(): string
|
||||
{
|
||||
$pdf = new \Mpdf\Mpdf();
|
||||
|
||||
// Check for paper size and page orientation
|
||||
$setup = $this->spreadsheet->getSheet($this->getSheetIndex() ?? 0)->getPageSetup();
|
||||
$orientation = $this->getOrientation() ?? $setup->getOrientation();
|
||||
$orientation = ($orientation === PageSetup::ORIENTATION_LANDSCAPE) ? 'L' : 'P';
|
||||
$printPaperSize = $this->getPaperSize() ?? $setup->getPaperSize();
|
||||
$paperSize = self::$paperSizes[$printPaperSize] ?? PageSetup::getPaperSizeDefault();
|
||||
|
||||
$ortmp = $orientation;
|
||||
$pdf->_setPageSize($paperSize, $ortmp);
|
||||
$pdf->DefOrientation = $orientation;
|
||||
$pdf->AddPageByArray([
|
||||
'orientation' => $orientation,
|
||||
'margin-left' => $this->inchesToMm($this->spreadsheet->getActiveSheet()->getPageMargins()->getLeft()),
|
||||
'margin-right' => $this->inchesToMm($this->spreadsheet->getActiveSheet()->getPageMargins()->getRight()),
|
||||
'margin-top' => $this->inchesToMm($this->spreadsheet->getActiveSheet()->getPageMargins()->getTop()),
|
||||
'margin-bottom' => $this->inchesToMm($this->spreadsheet->getActiveSheet()->getPageMargins()->getBottom()),
|
||||
]);
|
||||
|
||||
// Document info
|
||||
$pdf->SetTitle($this->spreadsheet->getProperties()->getTitle());
|
||||
$pdf->SetAuthor($this->spreadsheet->getProperties()->getCreator());
|
||||
$pdf->SetSubject($this->spreadsheet->getProperties()->getSubject());
|
||||
$pdf->SetKeywords($this->spreadsheet->getProperties()->getKeywords());
|
||||
$pdf->SetCreator($this->spreadsheet->getProperties()->getCreator());
|
||||
|
||||
$html = $this->generateHTMLAll();
|
||||
$bodyLocation = strpos($html, Html::BODY_LINE);
|
||||
// Make sure first data presented to Mpdf includes body tag
|
||||
// so that Mpdf doesn't parse it as content. Issue 2432.
|
||||
if ($bodyLocation !== false) {
|
||||
$bodyLocation += strlen(Html::BODY_LINE);
|
||||
$pdf->WriteHTML(substr($html, 0, $bodyLocation));
|
||||
$html = substr($html, $bodyLocation);
|
||||
}
|
||||
foreach (\array_chunk(\explode(PHP_EOL, $html), 1000) as $lines) {
|
||||
$pdf->WriteHTML(\implode(PHP_EOL, $lines));
|
||||
}
|
||||
|
||||
$html = $pdf->Output('', 'S');
|
||||
|
||||
parent::restoreStateAfterSave();
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert inches to mm.
|
||||
*
|
||||
* @param float $inches
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
private function inchesToMm($inches)
|
||||
{
|
||||
return $inches * 25.4;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,133 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* Karaka
|
||||
*
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package tests
|
||||
* @copyright Dennis Eichhorn
|
||||
* @license OMS License 1.0
|
||||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace phpOMS\tests\DataStorage\Session;
|
||||
|
||||
use phpOMS\DataStorage\Session\FileSessionHandler;
|
||||
use phpOMS\System\File\Local\Directory;
|
||||
|
||||
/**
|
||||
* @testdox phpOMS\tests\DataStorage\Session\FileSessionHandlerTest: File session handler
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
final class FileSessionHandlerTest extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
protected FileSessionHandler $sh;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() : void
|
||||
{
|
||||
if (\is_dir(__DIR__ . '/test')) {
|
||||
Directory::delete(__DIR__ . '/test');
|
||||
}
|
||||
|
||||
$this->sh = new FileSessionHandler(__DIR__ . '/test');
|
||||
}
|
||||
|
||||
protected function tearDown() : void
|
||||
{
|
||||
if (\is_dir(__DIR__ . '/test')) {
|
||||
Directory::delete(__DIR__ . '/test');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox A session id can be generated
|
||||
* @group framework
|
||||
*/
|
||||
public function testCreateSid() : void
|
||||
{
|
||||
self::assertMatchesRegularExpression('/^s\-[a-z0-9]+/', $this->sh->create_sid());
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox The session path can be accessed
|
||||
* @group framework
|
||||
*/
|
||||
public function testSessionPath() : void
|
||||
{
|
||||
self::assertTrue($this->sh->open(__DIR__ . '/test', ''));
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox A invalid session path cannot be accessed
|
||||
* @group framework
|
||||
*/
|
||||
public function testInvalidSessionPath() : void
|
||||
{
|
||||
self::assertFalse($this->sh->open(__DIR__ . '/invalid', ''));
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox A session can be closed
|
||||
* @group framework
|
||||
*/
|
||||
public function testSessionClose() : void
|
||||
{
|
||||
self::assertTrue($this->sh->close());
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox A valid session id can store and return data
|
||||
* @group framework
|
||||
*/
|
||||
public function testSessionInputOutput() : void
|
||||
{
|
||||
$id = $this->sh->create_sid();
|
||||
self::assertTrue($this->sh->write($id, 'test'));
|
||||
self::assertEquals('test', $this->sh->read($id));
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox A invalid session id doesn't return any data
|
||||
* @group framework
|
||||
*/
|
||||
public function testReadInvalidSessionId() : void
|
||||
{
|
||||
self::assertEquals('', $this->sh->read('invalid'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox A session can be destroyed
|
||||
* @group framework
|
||||
*/
|
||||
public function testSessionDestroy() : void
|
||||
{
|
||||
$id = $this->sh->create_sid();
|
||||
self::assertTrue($this->sh->write($id, 'test'));
|
||||
self::assertEquals('test', $this->sh->read($id));
|
||||
|
||||
$this->sh->destroy($id);
|
||||
self::assertEquals('', $this->sh->read($id));
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox Sessions can be removed based on a timeout
|
||||
* @group framework
|
||||
*/
|
||||
public function testSessionTimeoutDestroy() : void
|
||||
{
|
||||
$id = $this->sh->create_sid();
|
||||
self::assertTrue($this->sh->write($id, 'test'));
|
||||
self::assertEquals('test', $this->sh->read($id));
|
||||
|
||||
\sleep(2);
|
||||
|
||||
$this->sh->gc(0);
|
||||
self::assertEquals('', $this->sh->read($id));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,159 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* Karaka
|
||||
*
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package tests
|
||||
* @copyright Dennis Eichhorn
|
||||
* @license OMS License 1.0
|
||||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace phpOMS\tests\DataStorage\Session;
|
||||
|
||||
use phpOMS\DataStorage\Session\FileSession;
|
||||
|
||||
/**
|
||||
* @testdox phpOMS\tests\DataStorage\Session\FileSessionTest: File session handler
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
final class FileSessionTest extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
protected FileSession $session;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() : void
|
||||
{
|
||||
$this->session = new FileSession();
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox The session has the expected default values after initialization
|
||||
* @group framework
|
||||
*/
|
||||
public function testDefault() : void
|
||||
{
|
||||
self::assertNull($this->session->get('key'));
|
||||
self::assertFalse($this->session->isLocked());
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox Session data can be set and returned
|
||||
* @group framework
|
||||
*/
|
||||
public function testInputOutput() : void
|
||||
{
|
||||
self::assertTrue($this->session->set('test', 'value'));
|
||||
self::assertEquals('value', $this->session->get('test'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox Session data cannot be overwritten
|
||||
* @group framework
|
||||
*/
|
||||
public function testInvalidOverwrite() : void
|
||||
{
|
||||
$this->session->set('test', 'value');
|
||||
self::assertFalse($this->session->set('test', 'value2'));
|
||||
self::assertEquals('value', $this->session->get('test'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox Session data can be forced to overwrite
|
||||
* @group framework
|
||||
*/
|
||||
public function testOverwrite() : void
|
||||
{
|
||||
$this->session->set('test', 'value');
|
||||
self::assertTrue($this->session->set('test', 'value2', true));
|
||||
self::assertEquals('value2', $this->session->get('test'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox Session data can be removed
|
||||
* @group framework
|
||||
*/
|
||||
public function testRemove() : void
|
||||
{
|
||||
$this->session->set('test', 'value');
|
||||
self::assertTrue($this->session->remove('test'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox None-existing session data cannot be removed
|
||||
* @group framework
|
||||
*/
|
||||
public function testInvalidRemove() : void
|
||||
{
|
||||
$this->session->set('test', 'value');
|
||||
$this->session->remove('test');
|
||||
|
||||
self::assertFalse($this->session->remove('test'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox A session id can be set and returned
|
||||
* @group framework
|
||||
*/
|
||||
public function testSessionIdInputOutput() : void
|
||||
{
|
||||
$this->session->setSID('abc');
|
||||
self::assertEquals('abc', $this->session->getSID());
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox A session can be locked
|
||||
* @group framework
|
||||
*/
|
||||
public function testLockInputOutput() : void
|
||||
{
|
||||
$this->session->lock();
|
||||
self::assertTrue($this->session->isLocked());
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox Session data can be saved
|
||||
* @group framework
|
||||
*/
|
||||
public function testSave() : void
|
||||
{
|
||||
self::assertTrue($this->session->save());
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox Locked sessions cannot be saved
|
||||
* @group framework
|
||||
*/
|
||||
public function testInvalidLockSave() : void
|
||||
{
|
||||
$this->session->lock();
|
||||
self::assertFalse($this->session->save());
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox A locked session cannot add or change data
|
||||
* @group framework
|
||||
*/
|
||||
public function testLockInvalidSet() : void
|
||||
{
|
||||
$this->session->lock();
|
||||
self::assertFalse($this->session->set('test', 'value'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox A locked session cannot remove data
|
||||
* @group framework
|
||||
*/
|
||||
public function testLockInvalidRemove() : void
|
||||
{
|
||||
self::assertTrue($this->session->set('test', 'value'));
|
||||
$this->session->lock();
|
||||
self::assertFalse($this->session->remove('test'));
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user