0
1
Fork 0

One unique entry point from HTTP server

This commit is contained in:
Juan Ferrer Toribio 2016-08-26 14:43:45 +02:00
parent 25ddb17f35
commit 9812519677
46 changed files with 1579 additions and 202 deletions

View File

@ -2,7 +2,7 @@
require_once ('vn/lib/cli-app.php');
$cliApp = new Vn\Lib\CliApp ('hedera-web', 'rest');
$cliApp = new Vn\Lib\CliApp ('hedera-web');
$cliApp->run ();
?>

8
debian/cron.d vendored
View File

@ -1,2 +1,8 @@
MAILTO=webmaster
*/4 * * * * www-data php5 /usr/share/hedera-web/tpv/imap.php
*/4 * * * * root php /usr/share/hedera-web/cli.php -m tpv/confirm-mail
*/2 * * * * root php /usr/share/hedera-web/cli.php -m edi/load
0 23 * * * root php /usr/share/hedera-web/cli.php -m edi/clean
0 5 * * * root php /usr/share/hedera-web/cli.php -m edi/update
*/1 * * * * root php /usr/share/hedera-web/cli.php -m misc/mail
0 5 * * * root php /usr/share/hedera-web/cli.php -m misc/exchange-rate
45 14 20 11 * root php /usr/share/hedera-web/cli.php -m misc/exchange-rate

23
debian/install vendored
View File

@ -1,17 +1,12 @@
conf/* etc/hedera-web
vn usr/share/php
doc/* usr/share/doc/hedera-web
forms usr/share/hedera-web/web
image usr/share/hedera-web/web
js usr/share/hedera-web/web
locale usr/share/hedera-web/web
pages usr/share/hedera-web/web
reports usr/share/hedera-web/web
rest usr/share/hedera-web/web
rest-json usr/share/hedera-web/web
index.php usr/share/hedera-web/web
rest.php usr/share/hedera-web/web
rest-json.php usr/share/hedera-web/web
hedera.php usr/share/hedera-web/bin
tasks usr/share/hedera-web/bin
forms usr/share/hedera-web
image usr/share/hedera-web
js usr/share/hedera-web
locale usr/share/hedera-web
pages usr/share/hedera-web
reports usr/share/hedera-web
rest usr/share/hedera-web
index.php usr/share/hedera-web
cli.php usr/share/hedera-web

View File

@ -14,8 +14,13 @@ Vn.Contact = new Class
,refreshCaptcha: function ()
{
var url = 'rest.php?method=core/captcha';
this.$('captcha-img').src = url +'&stamp='+ new Date ().getTime ();
params = {
'srv': 'rest:core/captcha',
'stamp': new Date ().getTime ()
};
this.$('captcha-img').src = '?'+ Vn.Url.makeUri (params);
Vn.Url.makeUri (params)
}
,onSubmit: function ()

View File

@ -12,9 +12,8 @@
<t>OrCallUs</t>
</p>
<form
id="contact-form"
method="post"
action="json.php?method=misc/contact">
id="contact-form">
<input type="hidden" name="srv" value="json:misc/contact"/>
<div class="form-group">
<label><t>Name</t></label>
<input type="text" name="name"/>

View File

@ -8,7 +8,7 @@ Vn.Invoices = new Class
if (!invoiceId)
return;
var url = 'rest.php?method=invoice&invoice='+ invoiceId;
var url = 'rest.php?method=dms/invoice&invoice='+ invoiceId;
window.open (url, '_blank');
}
});

View File

@ -1,8 +1,8 @@
<?php
require_once ('vn/web/html-app.php');
require_once ('vn/web/app.php');
$htmlApp = new Vn\Web\HtmlApp ('hedera-web', 'pages');
$htmlApp->run ();
$webApp = new Vn\Web\App ('hedera-web');
$webApp->run ();
?>

View File

@ -2,9 +2,8 @@
<div id="main" class="htk-image-editor">
<form
id="form"
method="post"
action="json.php?method=image/upload"
enctype="multipart/form-data">
<input type="hidden" name="srv" value="json:image/upload"/>
<div class="form-group">
<label for="name"><t>FileName</t></label>
<input id="name" type="text" name="name" on-change="onNameChange"/>

View File

@ -21,10 +21,34 @@ Vn.JsonRequest = new Class
,send: function (params, callback)
{
var url = 'json.php?method='+ encodeURIComponent (this._methodName);
params['srv'] = 'json:'+ this._methodName;
this.sendWithUrl (params, callback, 'post', url);
}
,sendForm: function (form, callback)
{
var params = {};
var elements = form.elements;
for (var i = 0; i < elements.length; i++)
if (elements[i].name)
params[elements[i].name] = elements[i].value;
this.sendWithUrl (params, callback, form.method, form.action);
}
,sendFormMultipart: function (form, callback)
{
var formData = new FormData (form);
formData.append ('service', 'Json');
var request = new XMLHttpRequest ();
request.open (form.method, form.action, true);
request.onreadystatechange =
this._onStateChange.bind (this, request, callback);
request.send (new FormData (form));
}
,_onStateChange: function (request, callback)
{
if (request.readyState !== 4)
@ -63,26 +87,5 @@ Vn.JsonRequest = new Class
if (callback)
callback (this, data, error);
}
,sendForm: function (form, callback)
{
var params = {};
var elements = form.elements;
for (var i = 0; i < elements.length; i++)
if (elements[i].name)
params[elements[i].name] = elements[i].value;
this.sendWithUrl (params, callback, form.method, form.action);
}
,sendFormMultipart: function (form, callback)
{
var request = new XMLHttpRequest ();
request.open (form.method, form.action, true);
request.onreadystatechange =
this._onStateChange.bind (this, request, callback);
request.send (new FormData (form));
}
});

View File

@ -1,8 +0,0 @@
<?php
require_once ('vn/web/json-app.php');
$restApp = new Vn\Web\JsonApp ('hedera-web', 'rest');
$restApp->run ();
?>

View File

@ -1,8 +0,0 @@
<?php
require_once ('vn/web/rest-app.php');
$restApp = new Vn\Web\RestApp ('hedera-web', 'rest');
$restApp->run ();
?>

49
rest/edi/clean.php Normal file
View File

@ -0,0 +1,49 @@
<?php
require_once (__DIR__.'/lib/edi-method.php');
class Clean extends EdiMethod
{
function ediRun ()
{
$db = $this->getSysConn ();
$imap = $this->imap;
$cleanPeriod = $db->getValue ('SELECT clean_period FROM imap_config');
$deleted = 0;
$date = new DateTime (NULL);
$date->sub (new DateInterval ($cleanPeriod));
$filter = sprintf ('BEFORE "%s"', $date->format('D, j M Y'));
$folders = [
$this->imapConf['success_folder']
,$this->imapConf['error_folder']
];
foreach ($folders as $folder)
if (imap_reopen ($imap, $this->mailbox .'.'. $folder))
{
if ($messages = imap_search ($imap, $filter))
{
foreach ($messages as $message)
imap_delete ($imap, $message);
imap_expunge ($imap);
$count = count ($messages);
$deleted += $count;
}
else
$count = 0;
printf ('%d mails deleted from %s mailbox.'
,$count
,$folder
);
}
printf ('Total: %d mails deleted.', $deleted);
}
}
?>

165
rest/edi/lib/message.php Normal file
View File

@ -0,0 +1,165 @@
<?php
namespace Vn\Edi;
require_once (__DIR__.'/section.php');
class SectionInfo
{
var $schema;
var $parentInfo;
var $section;
}
class Message
{
var $section;
static function loadSchema ($schemaName)
{
$ediSchemaStr = file_get_contents ("vn/edi/schemas/$schemaName.json", TRUE);
if ($ediSchemaStr !== FALSE)
return json_decode ($ediSchemaStr, TRUE);
return NULL;
}
static function isEdiString (&$string)
{
return substr ($string, 0, 4) == 'UNB+';
}
function parse (&$string, &$schema = NULL)
{
global $delimiters;
if (!self::isEdiString ($string))
throw new \Exception ('Not an EDI string.');
$pos = 0;
$error = FALSE;
$endTag = NULL;
$firstLoop = TRUE;
$newSection = TRUE;
$info = new SectionInfo ();
$info->schema = $schema;
$info->parentInfo = NULL;
$info->section = NULL;
$topInfo = $info;
try {
while (TRUE)
{
$segment = $this->parseSegment ($string, $pos);
if (!$segment && (!$endTag || !$info))
break;
if (!$segment || ($segment && !$info))
throw new \Exception ();
if ($firstLoop)
{
if ($segment->name != $info->schema['mainTag'])
throw new \Exception ();
}
else
{
for ($i = $info; $i; $i = $i->parentInfo)
if (isset ($i->schema['childs'][$segment->name]))
{
$info = new SectionInfo ();
$info->schema = $i->schema['childs'][$segment->name];
$info->parentInfo = $i;
$newSection = TRUE;
break;
}
}
if ($newSection)
{
$section = new Section ();
$section->name = $segment->name;
$info->section = $section;
if ($info->parentInfo)
{
$section->parent = $info->parentInfo->section;
$section->parent->childs[$segment->name][] = $section;
}
if (isset ($info->schema['endTag']))
$endTag = $info;
$newSection = FALSE;
}
if ($endTag && $endTag->schema['endTag'] == $segment->name)
{
$endTag->section->segments[] = $segment;
$info = $endTag->parentInfo;
for ($i = $info; $i; $i = $i->parentInfo)
if (isset ($i->schema['endTag']))
{
$endTag = $i;
break;
}
}
else
$info->section->segments[] = $segment;
$firstLoop = FALSE;
}}
catch (\Exception $e)
{
throw new \Exception (sprintf ('Parse error, something is wrong near "%s"',
substr ($string, $pos, 10)));
}
$this->section = $topInfo->section;
}
function parseSegment (&$string, &$pos)
{
$empty = TRUE;
$values = [];
while (TRUE)
{
if (!isset ($string{$pos}))
return NULL;
if (in_array ($string{$pos}, ['+', ':', '\'']))
{
if (!$empty)
{
$values[] =
trim (substr ($string, $start, $pos - $start));
$empty = TRUE;
}
}
elseif ($empty)
{
$start = $pos;
$empty = FALSE;
}
if ($string{$pos} === '\'')
break;
$pos++;
}
$pos++;
$segment = new Segment ();
$segment->name = $values[0];
$segment->values = $values;
return $segment;
}
}
?>

43
rest/edi/lib/method.php Normal file
View File

@ -0,0 +1,43 @@
<?php
require_once ('vn/lib/method.php');
abstract class EdiMethod extends Vn\Lib\Method
{
protected $imap;
protected $imapConf;
protected $mailbox;
abstract function ediRun ();
function run ()
{
$db = $this->getSysConn ();
$db->selectDb ('edi');
$imapConf = $db->getRow (
'SELECT host, user, pass, success_folder, error_folder FROM imap_config');
$this->mailbox = sprintf ('{%s/imap/ssl/novalidate-cert}INBOX',
$imapConf['host']);
$imap = imap_open ($this->mailbox
,$imapConf['user']
,base64_decode ($imapConf['pass'])
);
$this->imap = $imap;
$this->imapConf = $imapConf;
if ($imap)
{
$this->ediRun ();
imap_expunge ($imap);
imap_close ($imap);
}
else
error_log (imap_last_error ());
}
}
?>

28
rest/edi/lib/section.php Normal file
View File

@ -0,0 +1,28 @@
<?php
namespace Vn\Edi;
require_once (__DIR__.'/segment.php');
class Section
{
var $name;
var $parent = NULL;
var $segments = [];
var $childs = [];
function getValue ($name, $key, $type = NULL, $subname = NULL)
{
foreach ($this->segments as $segment)
if ($segment->name == $name
&& (!$subname || $segment->values[1] == $subname))
return $segment->getValue ($key, $type);
if ($this->parent)
return $this->parent->getValue ($name, $key, $type, $subname);
return NULL;
}
}
?>

38
rest/edi/lib/segment.php Normal file
View File

@ -0,0 +1,38 @@
<?php
namespace Vn\Edi;
require_once ('vn/lib/type.php');
class Segment
{
var $name;
var $values = [];
function getValue ($key, $type = NULL)
{
if ($key < 0 || $key >= count ($this->values))
return NULL;
$v = $this->values[$key];
switch ($type)
{
case TYPE_DATE:
$tmp = new \Date ();
$tmp->setDate (substr ($v, 0, 4), substr ($v, 4, 2), substr ($v, 6, 2));
return $tmp;
case TYPE_TIME:
$tmp = new \Time ();
$tmp->setTime (substr ($v, 0, 2), substr ($v, 2, 2));
return $tmp;
case TYPE_DOUBLE:
case TYPE_INTEGER:
set_type ($v, $type);
default:
return $v;
}
}
}
?>

221
rest/edi/load.php Normal file
View File

@ -0,0 +1,221 @@
<?php
require_once (__DIR__.'/lib/method.php');
require_once (__DIR__.'/lib/edi.php');
class Load extends EdiMethod
{
function ediRun ()
{
$db = $this->getSysConn ();
$this->ediSchema = Edi\Message::loadSchema ('CLOCKT');
if (!$this->ediSchema)
throw new Exception ('Can not load EDI schema.');
$this->params = $db->query (
'SELECT code, name, subname, position, type, required FROM param');
$inbox = imap_search ($this->imap, 'ALL');
if ($inbox)
{
foreach ($inbox as $msg)
$this->loadMail ($msg);
$inboxCount = count ($inbox);
if ($inboxCount > 0)
printf ('Total: %d messages readed.', $inboxCount);
}
}
function loadMail ($msg)
{
$db = $this->getSysConn ();
$imap = $this->imap;
// Gets EKT messages from email
$msgStructure = imap_fetchstructure ($imap, $msg);
$result = [];
// Gets the mail sender and Message-ID
$header = imap_headerinfo ($imap, $msg);
$from = $header->from;
$mailId = trim ($header->message_id, '<>');
if ($from && count ($from) > 0)
$sender = $from[0]->mailbox .'@'. $from[0]->host;
else
$sender = NULL;
// Searches the EDI message on mail parts
$matchTypes = [TYPEAPPLICATION, TYPETEXT];
$this->imapFindParts ($msgStructure, $matchTypes, [], $result);
$count = 0;
$error = NULL;
foreach ($result as $msgSection)
try
{
$part = imap_bodystruct ($imap, $msg, $msgSection);
$ediString = imap_fetchbody ($imap, $msg, $msgSection);
switch ($part->encoding)
{
case ENCBASE64:
$ediString = imap_base64 ($ediString);
break;
case ENCQUOTEDPRINTABLE:
$ediString = imap_qprint ($ediString);
break;
}
if (!Edi\Message::isEdiString ($ediString))
continue;
// Creates the EDI object and loads its exchanges
$ediMessage = new Edi\Message ();
$ediMessage->parse ($ediString, $this->ediSchema);
$db->query ('START TRANSACTION');
$db->query ('CALL message_new (#mailId, #sender, @message)',
[
'mailId' => $mailId,
'sender' => $sender
]);
$unb = $ediMessage->section;
$unhs = $unb->childs['UNH'];
foreach ($unhs as $unh)
foreach ($lins = $unh->childs['LIN'] as $lin)
{
$ediValues = [];
// Gets the exchange params
$this->params->data_seek (0);
while ($row = $this->params->fetch_assoc ())
{
switch ($row['type'])
{
case 'INTEGER':
$type = TYPE_INTEGER;
break;
case 'DOUBLE':
$type = TYPE_DOUBLE;
break;
case 'DATE':
$type = TYPE_DATE;
break;
case 'TIME':
$type = TYPE_TIME;
break;
default:
$type = TYPE_STRING;
}
$value = $lin->getValue (
$row['name'], $row['position'], $type, $row['subname']);
if (!isset ($value) && $row['required'])
throw new Exception ('Missing required parameter: '. $row['code']);
$ediValues[$row['code']] = $value;
}
// Gets the exchange features
$res = $db->query (
'SELECT presentation_order, feature '
.'FROM item_feature WHERE item_id = #ref '
.'AND expiry_date IS NULL'
,$ediValues
);
if ($res)
while ($row = $res->fetch_assoc ())
{
$value = $lin->getValue ('IMD', 2, TYPE_INTEGER, $row['feature']);
$ediValues['s'.$row['presentation_order']] = $value;
}
else
throw new Exception ('Can\'t get the item features.');
for ($i = 1; $i <= 6; $i++)
if (!isset ($ediValues['s'.$i]))
$ediValues['s'.$i] = NULL;
// Adds the exchange to the Database
$res = $db->queryFromFile ('sql/batch-add', $ediValues);
if (!$res)
throw new Exception ('Failed to insert the line.');
$count++;
}
$db->query ('COMMIT');
}
catch (Exception $e)
{
$db->query ('ROLLBACK');
$error = $e->getMessage ();
break;
}
if (!$error && $count == 0)
$error = 'EDI messages not found.';
// Logs information of realized operations
if (!$error)
{
$folder = $this->imapConf['success_folder'];
printf ('EDI: Mail loaded with %d lines.', $count);
}
else
{
$folder = $this->imapConf['error_folder'];
printf ('EDI: Mail error: %s', $error);
}
// Moves the mail to another folder
$folder = sprintf ('INBOX.%s', $folder);
if (!imap_mail_move ($imap, $msg, $folder))
error_log ('Can\'t move message to %s: %s'
,$folder
,imap_last_error ()
);
}
function imapFindParts (&$part, &$matchTypes, $section, &$result)
{
if (in_array ($part->type, $matchTypes))
{
if (count ($section) > 0)
$result[] = implode ('.', $section);
else
$result[] = '1';
}
elseif ($part->type == TYPEMULTIPART)
foreach ($part->parts as $i => $subpart)
{
array_push ($section, $i + 1);
$this->imapFindParts ($subpart, $matchTypes, $section, $result);
array_pop ($section);
}
}
}
?>

View File

@ -0,0 +1,169 @@
/**
* Adds a new lot, generates its barcode
* inserts/updates de record on table #vn2008.buy_edi
**/
USE edi;
DROP PROCEDURE IF EXISTS batch_new;
DELIMITER $$
CREATE PROCEDURE batch_new (
v_message INT
,v_type MEDIUMINT
,v_delivery_number BIGINT
,v_fec DATE
,v_hor TIME
,v_ref INT
,v_agj INT
,v_cat VARCHAR(2)
,v_pac INT
,v_sub MEDIUMINT
,v_kop INT
,v_ptd VARCHAR(6)
,v_pro MEDIUMINT
,v_ori VARCHAR(3)
,v_ptj MEDIUMINT
,v_qty INT
,v_pri DOUBLE
,v_klo SMALLINT
,v_s1 VARCHAR(3)
,v_s2 VARCHAR(3)
,v_s3 VARCHAR(3)
,v_s4 VARCHAR(4)
,v_s5 VARCHAR(3)
,v_s6 VARCHAR(3)
,v_k1 SMALLINT
,v_k2 SMALLINT
,v_p1 TINYINT
,v_p2 TINYINT
,v_auction SMALLINT
,v_package INT
)
BEGIN
DECLARE v_edi INT;
DECLARE v_barcode CHAR(15) DEFAULT NULL;
DECLARE v_is_duplicated BOOLEAN DEFAULT FALSE;
DECLARE v_update_existent BOOLEAN DEFAULT FALSE;
DECLARE CONTINUE HANDLER FOR 1062 -- ER_DUP_KEY
SET v_is_duplicated = TRUE;
-- Genera el código de barras
IF v_agj != 0 AND v_agj IS NOT NULL
THEN
SET v_barcode = CONCAT(
LPAD(v_auction, 2, 0),
LPAD(IFNULL(v_klo, 99), 2, 0),
LPAD(DAYOFYEAR(v_fec), 3, 0),
IF(v_klo IS NULL OR v_klo = 99,
LPAD(v_agj, 7, 0),
CONCAT(LPAD(v_agj, 5, 0), '01')
),
'0'
);
END IF;
IF v_kop IS NULL
THEN
SELECT default_kop INTO v_kop FROM config;
END IF;
-- Inserta el nuevo EKT
INSERT INTO vn2008.buy_edi SET
barcode = IFNULL(v_barcode, barcode)
,delivery_number = v_delivery_number
,entry_year = YEAR(v_fec)
,fec = v_fec
,hor = v_hor
,ref = v_ref
,agj = v_agj
,cat = v_cat
,pac = v_pac
,sub = v_sub
,kop = v_kop
,ptd = v_ptd
,pro = v_pro
,ori = v_ori
,ptj = v_ptj
,qty = v_qty
,pri = v_pri
,klo = v_klo
,s1 = v_s1
,s2 = v_s2
,s3 = v_s3
,s4 = v_s4
,s5 = v_s5
,s6 = v_s6
,k01 = v_k1
,k02 = v_k2
,k03 = v_p1
,k04 = v_p2
,auction = v_auction
,package = v_package;
-- Si el EKT está duplicado y el que habia en la tabla era uno
-- provisional, lo actualiza con los nuevos valores.
IF NOT v_is_duplicated
THEN
SET v_edi = LAST_INSERT_ID();
CALL edi_load (v_edi);
ELSEIF v_delivery_number != 0
AND v_delivery_number IS NOT NULL
THEN
SELECT id INTO v_edi
FROM vn2008.buy_edi
WHERE delivery_number = v_delivery_number;
SELECT COUNT(*) = 0 INTO v_update_existent
FROM vn2008.buy_edi e
JOIN batch b ON b.buy_edi_id = e.id
JOIN config c
WHERE e.delivery_number = v_delivery_number
AND b.type_id != c.presale_id;
END IF;
IF v_update_existent
THEN
UPDATE vn2008.buy_edi SET
barcode = IFNULL(v_barcode, barcode)
,fec = v_fec
,hor = v_hor
,ref = v_ref
,agj = v_agj
,cat = v_cat
,pac = v_pac
,sub = v_sub
,kop = v_kop
,ptd = v_ptd
,pro = v_pro
,ori = v_ori
,ptj = v_ptj
,qty = v_qty
,pri = v_pri
,klo = v_klo
,s1 = v_s1
,s2 = v_s2
,s3 = v_s3
,s4 = v_s4
,s5 = v_s5
,s6 = v_s6
,k01 = v_k1
,k02 = v_k2
,k03 = v_p1
,k04 = v_p2
,auction = v_auction
,package = v_package
WHERE id = v_edi;
END IF;
-- Registra el lote
INSERT INTO batch SET
message_id = v_message
,type_id = v_type
,buy_edi_id = v_edi;
END$$
DELIMITER ;

164
rest/edi/plsql/edi_load.sql Normal file
View File

@ -0,0 +1,164 @@
/**
* Creates a buy line from an EDI lot.
*
* @param v_edi The EDI id
**/
USE edi;
DROP PROCEDURE IF EXISTS edi_load;
DELIMITER $$
CREATE PROCEDURE edi_load (v_edi INT)
BEGIN
DECLARE v_ref INT;
DECLARE v_buy INT;
DECLARE v_item INT;
DECLARE v_qty INT;
DECLARE v_package INT;
DECLARE v_is_lot BOOLEAN;
-- Carga los datos necesarios del EKT
SELECT ref, qty, package INTO v_ref, v_qty, v_package
FROM vn2008.buy_edi e
LEFT JOIN item i ON e.ref = i.id
WHERE e.id = v_edi;
-- Inserta el cubo si no existe
IF v_package = 800
THEN
SET v_package = 800 + v_qty;
INSERT IGNORE INTO vn2008.Cubos SET
Id_Cubo = v_package,
x = 7200 / v_qty,
y = 1;
ELSE
INSERT IGNORE INTO vn2008.Cubos (Id_Cubo, X, Y, Z)
SELECT bucket_id, ROUND(x_size/10), ROUND(y_size/10), ROUND(z_size/10)
FROM bucket WHERE bucket_id = v_package;
IF ROW_COUNT() > 0
THEN
INSERT INTO vn2008.mail SET
`subject` = 'Cubo añadido',
`text` = CONCAT('Se ha añadido el cubo: ', v_package),
`to` = 'ekt@verdnatura.es';
END IF;
END IF;
-- Intenta obtener el artículo en base a los atributos holandeses
INSERT IGNORE INTO item_track SET
item_id = v_ref;
SELECT c.Id_Compra, c.Id_Article INTO v_buy, v_item
FROM vn2008.buy_edi e
JOIN item_track t ON t.item_id = e.ref
LEFT JOIN vn2008.buy_edi l ON l.ref = e.ref
LEFT JOIN vn2008.Compres c ON c.buy_edi_id = l.id
JOIN vn2008.config cfg
WHERE e.id = v_edi
AND l.id != v_edi
AND c.Id_Article != cfg.generic_item
AND IF(t.s1, l.s1 = e.s1, TRUE)
AND IF(t.s2, l.s2 = e.s2, TRUE)
AND IF(t.s3, l.s3 = e.s3, TRUE)
AND IF(t.s4, l.s4 = e.s4, TRUE)
AND IF(t.s5, l.s5 = e.s5, TRUE)
AND IF(t.s6, l.s6 = e.s6, TRUE)
AND IF(t.kop, l.kop = e.kop, TRUE)
AND IF(t.pac, l.pac = e.pac, TRUE)
AND IF(t.cat, l.cat = e.cat, TRUE)
AND IF(t.ori, l.ori = e.ori, TRUE)
AND IF(t.pro, l.pro = e.pro, TRUE)
AND IF(t.sub, l.sub = e.sub, TRUE)
AND IF(t.package, l.package = e.package, TRUE)
AND c.Id_Article < 170000
ORDER BY l.now DESC, c.Id_Compra ASC LIMIT 1;
-- Determina si el articulo se vende por lotes
IF v_item
THEN
SELECT COUNT(*) > 0 INTO v_is_lot
FROM vn2008.Articles a
LEFT JOIN vn2008.Tipos t ON t.tipo_id = a.tipo_id
WHERE a.Id_Article = v_item
AND t.`transaction`;
-- Si el articulo se vende por lotes se inserta un nuevo artículo
IF v_is_lot
THEN
INSERT INTO vn2008.Articles (
Article
,Medida
,Categoria
,Id_Origen
,iva_group_id
,Foto
,Color
,Codintrastat
,tipo_id
,Tallos
)
SELECT
i.`name`
,IFNULL(e.s1, e.pac)
,e.cat
,IFNULL(o.id, 17)
,IFNULL(a.iva_group_id, 1)
,a.Foto
,a.Color
,a.Codintrastat
,IFNULL(a.tipo_id, 10)
,IF(a.tipo_id = 15, 0, 1)
FROM vn2008.buy_edi e
LEFT JOIN item i ON i.id = e.ref
LEFT JOIN vn2008.Origen o ON o.Abreviatura = e.ori
LEFT JOIN vn2008.Articles a ON a.Id_Article = v_item
WHERE e.id = v_edi;
SET v_item = LAST_INSERT_ID();
END IF;
END IF;
-- Inserta la compra asociada al EKT
INSERT INTO vn2008.Compres
(
Id_Entrada
,buy_edi_id
,Costefijo
,Id_Article
,Nicho
,grouping
,caja
,Packing
,Cantidad
,Productor
,Etiquetas
,Id_Cubo
)
SELECT
cfg.edi_entry
,v_edi
,(@t := IF(a.Tallos, a.Tallos, 1)) * e.pri
,IFNULL(v_item, cfg.generic_item)
,a.Nicho
,IFNULL(c.grouping, e.pac)
,IFNULL(c.caja, TRUE)
,@pac := e.pac / @t
,@pac * e.qty
,s.company_name
,e.qty
,IFNULL(c.Id_Cubo, e.package)
FROM vn2008.buy_edi e
LEFT JOIN vn2008.Compres c ON c.Id_Compra = v_buy
LEFT JOIN vn2008.Articles a ON a.Id_Article = c.Id_Article
LEFT JOIN supplier s ON e.pro = s.supplier_id
JOIN vn2008.config cfg
WHERE e.id = v_edi
LIMIT 1;
END$$
DELIMITER ;

View File

@ -0,0 +1,27 @@
/**
* Registers an email.
*
* @param v_mail_id Message-ID of email
* @param v_sender Origin email id
**/
USE edi;
DROP PROCEDURE IF EXISTS message_new;
DELIMITER $$
CREATE PROCEDURE message_new (
v_mail_id VARCHAR(100)
,v_sender VARCHAR(150)
,OUT v_message_id INT
)
BEGIN
DECLARE v_sender_id INT;
SELECT id INTO v_sender_id FROM mail
WHERE mail = v_sender;
INSERT IGNORE INTO message SET
sender_id = v_sender_id
,mail_id = v_mail_id;
SET v_message_id = LAST_INSERT_ID();
END$$
DELIMITER ;

View File

@ -0,0 +1,15 @@
{
"mainTag": "UNB",
"endTag": "UNZ",
"childs": {
"UNH": {
"endTag": "UNT",
"mandatory": true,
"childs": {
"LIN": {
"mandatory": true
}
}
}
}
}

View File

@ -0,0 +1,6 @@
CALL batch_new (
@message, #bgm, #aaj, #fec, #hor, #ref, #agj, #cat, #pac,
#sub, #kop, #ptd, #pro, #ori, #ptj, #qty, #pri, #klo, #s1, #s2, #s3,
#s4, #s5, #s6, #k1, #k2, #p1, #p2, #auction, #package
)

14
rest/edi/sql/bucket.sql Normal file
View File

@ -0,0 +1,14 @@
LOAD DATA LOCAL INFILE #file
INTO TABLE bucket
FIELDS TERMINATED BY ';'
LINES TERMINATED BY '\n' (@col1, @col2, @col3, @col4, @col5, @col6, @col7, @col8, @col9, @col10, @col11, @col12)
SET
bucket_id = @col2,
bucket_type_id = @col4,
description = @col5,
x_size = @col6,
y_size = @col7,
z_size = @col8,
entry_date = STR_TO_DATE(@col10, '%Y%m%d'),
expiry_date = IFNULL(NULL,STR_TO_DATE(@col11, '%Y%m%d')),
change_date_time = STR_TO_DATE(@col12, '%Y%m%d%H%i')

View File

@ -0,0 +1,10 @@
LOAD DATA LOCAL INFILE #file
INTO TABLE bucket_type
FIELDS TERMINATED BY ';'
LINES TERMINATED BY '\n' (@col1, @col2, @col3, @col4, @col5, @col6)
SET
bucket_type_id = @col2,
description = @col3,
entry_date = STR_TO_DATE(@col4, '%Y%m%d'),
expiry_date = IFNULL(NULL,STR_TO_DATE(@col5, '%Y%m%d')),
change_date_time = STR_TO_DATE(@col6, '%Y%m%d%H%i')

11
rest/edi/sql/feature.sql Normal file
View File

@ -0,0 +1,11 @@
LOAD DATA LOCAL INFILE #file
INTO TABLE `feature`
FIELDS TERMINATED BY ';'
LINES TERMINATED BY '\n' (@col1, @col2, @col3, @col4, @col5, @col6, @col7)
SET
item_id = @col2,
feature_type_id = @col3,
feature_value = @col4,
entry_date = STR_TO_DATE(@col5, '%Y%m%d'),
expiry_date = IFNULL(NULL,STR_TO_DATE(@col6, '%Y%m%d')),
change_date_time = STR_TO_DATE(@col7, '%Y%m%d%H%i')

10
rest/edi/sql/genus.sql Normal file
View File

@ -0,0 +1,10 @@
LOAD DATA LOCAL INFILE #file
INTO TABLE genus
FIELDS TERMINATED BY ';'
LINES TERMINATED BY '\n' (@col1, @col2, @col3, @col4, @col5, @col6)
SET
genus_id = @col2,
latin_genus_name = @col3,
entry_date = STR_TO_DATE(@col4, '%Y%m%d'),
expiry_date = IFNULL(NULL,STR_TO_DATE(@col5, '%Y%m%d')),
change_date_time = STR_TO_DATE(@col6, '%Y%m%d%H%i')

13
rest/edi/sql/item.sql Normal file
View File

@ -0,0 +1,13 @@
LOAD DATA LOCAL INFILE #file
INTO TABLE item
FIELDS TERMINATED BY ';'
LINES TERMINATED BY '\n' (@col1, @col2, @col3, @col4, @col5, @col6, @col7, @col8, @col9, @col10, @col11, @col12)
SET
id = @col2,
product_name = @col4,
name = @col5,
plant_id = @col7,
group_id = @col9,
entry_date = STR_TO_DATE(@col10, '%Y%m%d'),
expiry_date = IFNULL(NULL,STR_TO_DATE(@col11, '%Y%m%d')),
change_date_time = STR_TO_DATE(@col12, '%Y%m%d%H%i')

View File

@ -0,0 +1,12 @@
LOAD DATA LOCAL INFILE #file
INTO TABLE `item_feature`
FIELDS TERMINATED BY ';'
LINES TERMINATED BY '\n' (@col1, @col2, @col3, @col4, @col5, @col6, @col7, @col8)
SET
item_id = @col2,
feature = @col3,
regulation_type = @col4,
presentation_order = @col5,
entry_date = STR_TO_DATE(@col6, '%Y%m%d'),
expiry_date = IFNULL(NULL,STR_TO_DATE(@col7, '%Y%m%d')),
change_date_time = STR_TO_DATE(@col8, '%Y%m%d%H%i')

View File

@ -0,0 +1,10 @@
LOAD DATA LOCAL INFILE #file
INTO TABLE item_group
FIELDS TERMINATED BY ';'
LINES TERMINATED BY '\n' (@col1, @col2, @col3, @col4, @col5, @col6)
SET
group_code = @col2,
dutch_group_description = @col3,
entry_date = STR_TO_DATE(@col4, '%Y%m%d'),
expiry_date = IFNULL(NULL,STR_TO_DATE(@col5, '%Y%m%d')),
change_date_time = STR_TO_DATE(@col6, '%Y%m%d%H%i')

11
rest/edi/sql/plant.sql Normal file
View File

@ -0,0 +1,11 @@
LOAD DATA LOCAL INFILE #file
INTO TABLE plant
FIELDS TERMINATED BY ';'
LINES TERMINATED BY '\n' (@col1, @col2, @col3, @col4, @col5, @col6, @col7, @col8, @col9)
SET
plant_id = @col3,
genus_id = @col4,
specie_id = @col5,
entry_date = STR_TO_DATE(@col7, '%Y%m%d'),
expiry_date = IFNULL(NULL,STR_TO_DATE(@col8, '%Y%m%d')),
change_date_time = STR_TO_DATE(@col9, '%Y%m%d%H%i')

11
rest/edi/sql/specie.sql Normal file
View File

@ -0,0 +1,11 @@
LOAD DATA LOCAL INFILE #file
INTO TABLE specie
FIELDS TERMINATED BY ';'
LINES TERMINATED BY '\n' (@col1, @col2, @col3, @col4, @col5, @col6, @col7)
SET
specie_id = @col2,
genus_id = @col3,
latin_species_name = @col4,
entry_date = STR_TO_DATE(@col5, '%Y%m%d'),
expiry_date = IFNULL(NULL,STR_TO_DATE(@col6, '%Y%m%d')),
change_date_time = STR_TO_DATE(@col7, '%Y%m%d%H%i')

10
rest/edi/sql/supplier.sql Normal file
View File

@ -0,0 +1,10 @@
LOAD DATA LOCAL INFILE #file
INTO TABLE supplier
FIELDS TERMINATED BY ';'
LINES TERMINATED BY '\n' (@col1, @col2, @col3, @col4, @col5, @col6, @col7, @col8, @col9, @col10, @col11, @col12, @col13, @col14, @col15, @col16, @col17, @col18, @col19, @col20)
SET
supplier_id = @col4,
company_name = @col3,
entry_date = STR_TO_DATE(@col9, '%Y%m%d'),
expiry_date = IFNULL(NULL,STR_TO_DATE(@col10, '%Y%m%d')),
change_date_time = STR_TO_DATE(@col11, '%Y%m%d%H%i')

11
rest/edi/sql/type.sql Normal file
View File

@ -0,0 +1,11 @@
LOAD DATA LOCAL INFILE #file
INTO TABLE `type`
FIELDS TERMINATED BY ';'
LINES TERMINATED BY '\n' (@col1, @col2, @col3, @col4, @col5, @col6, @col7)
SET
type_id = @col2,
type_group_id = @col3,
description = @col4,
entry_date = STR_TO_DATE(@col5, '%Y%m%d'),
expiry_date = IFNULL(NULL,STR_TO_DATE(@col6, '%Y%m%d')),
change_date_time = STR_TO_DATE(@col7, '%Y%m%d%H%i')

11
rest/edi/sql/value.sql Normal file
View File

@ -0,0 +1,11 @@
LOAD DATA LOCAL INFILE #file
INTO TABLE `value`
FIELDS TERMINATED BY ';'
LINES TERMINATED BY '\n' (@col1, @col2, @col3, @col4, @col5, @col6, @col7)
SET
type_id = @col2,
type_value = @col3,
type_description = @col4,
entry_date = STR_TO_DATE(@col5, '%Y%m%d'),
expiry_date = IFNULL(NULL,STR_TO_DATE(@col6, '%Y%m%d')),
change_date_time = STR_TO_DATE(@col7, '%Y%m%d%H%i')

119
rest/edi/update.php Normal file
View File

@ -0,0 +1,119 @@
<?php
require_once ('vn/lib/method.php');
class Update extends Vn\Lib\Method
{
function run ()
{
$db = $this->getSysConn ();
$db->selectDb ('edi');
//$db->options (MYSQLI_OPT_LOCAL_INFILE, TRUE);
$tmpDir = '/tmp/floricode';
// Establece una conexión FTP
$ftpConf = $db->getRow ('SELECT host, user, password FROM ftp_config');
$ftpConn = ftp_connect ($ftpConf['host']);
if (!$ftpConn)
throw new Exception ('Can not connect to '. $ftpConf['host']);
if (!ftp_login ($ftpConn, $ftpConf['user'], $ftpConf['password']))
throw new Exception ('Can not login to '. $ftpConf['user'] .'@'. $ftpConf['host']);
// Obtiene el listado de tablas a actualizar
set_time_limit (0);
$res = $db->query (
'SELECT file_name, to_table, file, updated FROM file_config');
$dwFiles = [];
if (!file_exists ($tmpDir))
mkdir ($tmpDir);
while ($row = $res->fetch_assoc ())
try {
$file = $row['file'];
$table = $row['to_table'];
$baseName = $row['file_name'];
if ($row['updated'])
$updated = DateTime::createFromFormat ('Y-m-d', $row['updated']);
else
$updated = NULL;
$remoteFile = "codes/$file.ZIP";
$zipFile = "$tmpDir/$file.zip";
$ucDir = "$tmpDir/$file";
// Intenta descargar y descomprimir el fichero con los datos
if (!isset ($dwFiles[$file]))
{
$dwFiles[$file] = TRUE;
if (!ftp_get ($ftpConn, $zipFile, $remoteFile, FTP_BINARY))
throw new Exception ("Error downloading $remoteFile to $zipFile");
$zip = new ZipArchive;
if ($zip->open ($zipFile) !== TRUE)
throw new Exception ("Can not open $zipFile");
@mkdir ($ucDir, 0774, TRUE);
if (!$zip->extractTo ($ucDir))
throw new Exception ("Can not uncompress file $zipFile");
$zip->close();
unlink ($zipFile);
}
foreach (glob ("$ucDir/$baseName*.txt") as $fileName)
break;
if (!$fileName)
throw new Exception ("Import file for table $table does not exist");
// Si los datos están actualizados omite la tabla
$lastUpdated = substr ($fileName, -10, 6);
$lastUpdated = DateTime::createFromFormat ('dmy', $lastUpdated);
if ($updated && $lastUpdated <= $updated)
continue;
// Actualiza los datos de la tabla
$importQuery = $db->loadFromFile ("sql/$table", ['file' => $fileName]);
$db->multiQuery (
"START TRANSACTION;
DELETE FROM $table;
$importQuery;
UPDATE file_config SET updated = # WHERE file_name = #;
COMMIT;",
[$lastUpdated, $baseName]
);
do {
$db->storeResult ();
}
while ($db->moreResults () && $db->nextResult ());
}
catch (Exception $e)
{
$db->query ('ROLLBACK');
error_log ($e->getMessage ());
}
shell_exec ("rm -R $tmpDir");
ftp_close ($ftpConn);
}
}
?>

View File

@ -64,7 +64,7 @@ class Resize extends Vn\Lib\Method
catch (\Exception $e) {}
}
echo "$count files resized";
echo "$count files resized.\n";
}
}

View File

@ -86,7 +86,7 @@ class Sync extends Vn\Lib\Method
$this->cleanImages ($schema, $size, $map);
}
echo "Syncronization finished";
echo "Syncronization finished.\n";
}
function cleanImages ($schema, $size, &$map)

54
rest/misc/exchange-rate.php Executable file
View File

@ -0,0 +1,54 @@
<?php
require_once ('vn/lib/method.php');
/**
* Ejemplo:
* <Cube><Cube time="2010-12-10"><Cube currency="USD" rate="1.3244"/>
**/
class ExchangeRate extends Vn\Lib\Method
{
function run ()
{
$db = $this->getSysConn ();
// Indica la URL del archivo
$xml = new SimpleXMLElement (
'http://www.ecb.europa.eu/stats/eurofxref/eurofxref-hist-90d.xml', 0, TRUE);
$date = $db->getValue ("SELECT MAX(date) fecha FROM reference_rate");
$maxDate = $date ? DateTime::createFromFormat ('Y-m-d', $date) : NULL;
foreach ($xml->Cube[0]->Cube as $cube)
{
$xmlDate = new DateTime ($cube['time']);
// Si existen datos más recientes de la máxima fecha los añade
if ($maxDate < $xmlDate)
foreach ($cube->Cube as $subCube)
if ($subCube['currency'] == 'USD')
{
$params = [
'date' => $xmlDate,
'rate' => $subCube['rate']
];
$db->query (
'REPLACE INTO reference_rate (moneda_id, date, rate)
VALUES (2, #date, #rate)',
$params
);
$db->query (
'REPLACE INTO reference_rate (moneda_id, date, rate)
VALUES (2, TIMESTAMPADD(DAY, 1, #date), #rate)',
$params
);
}
}
$db->queryFromFile (__DIR__.'/exrate-add');
}
}
?>

6
rest/misc/exrate-add.sql Normal file
View File

@ -0,0 +1,6 @@
INSERT INTO reference_rate (moneda_id, date, rate)
SELECT 2, TIMESTAMPADD (DAY, 1, r1.date), r1.rate
FROM reference_rate r1
LEFT JOIN reference_rate r2
ON TIMESTAMPADD(DAY, 1, r1.date) = r2.date
WHERE r2.date IS NULL AND r1.date < TIMESTAMPADD (DAY, -1, CURDATE())

91
rest/misc/mail.php Executable file
View File

@ -0,0 +1,91 @@
<?php
require_once ('vn/lib/method.php');
require_once ('libphp-phpmailer/PHPMailerAutoload.php');
class Mail extends Vn\Lib\Method
{
function run ()
{
$db = $this->getSysConn ();
$db->query ('START TRANSACTION');
$conf = $db->getRow (
'SELECT host, port, secure, sender, sender_name, user, password
FROM hedera.mail_config'
);
$res = $db->query (
'SELECT * FROM mail WHERE sent = 0 ORDER BY DATE_ODBC DESC
LIMIT 20 FOR UPDATE');
while ($row = $res->fetch_assoc ())
{
$sent = 1;
$status = 'OK';
try {
if (!preg_match ('/^[\w\._%-]+@[\w\.-]+\.[A-Za-z]{2,4}$/', $row['to']))
throw new Exception ('Destination mail has invalid sintax');
$mail = new PHPMailer ();
$mail->isSMTP ();
$mail->Host = $conf['host'];
if (!empty ($conf['user']))
{
$mail->SMTPAuth = TRUE;
$mail->Username = $conf['user'];
$mail->Password = base64_decode ($conf['password']);
}
else
$mail->SMTPAuth = FALSE;
if ($conf['secure'])
{
$mail->SMTPSecure = 'ssl';
$mail->Port = 465;
}
$mail->setFrom ($conf['sender'], $conf['sender_name']);
$mail->AddReplyTo ($row['reply_to'], 'Att. Cliente');
if (strpos ($row['to'], ','))
$mailList = explode (',', $row['to']);
else
$mailList = explode (';', $row['to']);
foreach ($mailList as $mailTo)
$mail->AddAddress ($mailTo);
$mail->Subject = $row['subject'];
$mail->Body = ' '. $row['text'];
$mail->CharSet = 'UTF-8';
if (!empty ($row['path']))
{
$attachment = '/mnt/storage/pdfs/'. $row['path'];
if (file_exists ($attachment))
$mail->AddAttachment ($attachment, '');
else
throw new Exception ('Attachment file could not be found: '. $attachment);
}
if (!$mail->Send ())
throw new Exception ('Send error: '.$mail->ErrorInfo);
}
catch (Exception $e)
{
$sent = 2;
$status = $e->getMessage ();
}
$db->query ('UPDATE mail SET sent = #, error = # WHERE id = #',
[$sent, $status, $row['id']]);
}
$db->query ('COMMIT');
}
}
?>

View File

@ -31,6 +31,7 @@ class ConfirmMail extends Vn\Lib\Method
// Fetchs and confirms new transaction mails
$count = 0;
$inbox = imap_search ($imap, 'ALL');
if ($inbox)
@ -50,6 +51,8 @@ class ConfirmMail extends Vn\Lib\Method
// Confirms the transaction
$success = FALSE;
try {
$success = Tpv::confirm ($db, $params);
}
@ -67,13 +70,15 @@ class ConfirmMail extends Vn\Lib\Method
if (!imap_mail_move ($imap, $msg, "INBOX.$folder"))
trigger_error (imap_last_error (), E_USER_WARNING);
$count++;
}
imap_expunge ($imap);
// Cleans the old mails
$deleted = NULL;
$deleted = 0;
if (rand (1, 20) == 1)
{
@ -82,7 +87,6 @@ class ConfirmMail extends Vn\Lib\Method
,$imapConf['error_folder']
);
$deleted = 0;
$date = new \DateTime (NULL);
$date->sub (new \DateInterval ($imapConf['clean_period']));
$filter = sprintf ('BEFORE "%s"', $date->format('D, j M Y'));
@ -99,7 +103,7 @@ class ConfirmMail extends Vn\Lib\Method
}
}
echo "TPV: $count mails processed, $deleted mails deleted";
echo "$count mails processed, $deleted mails deleted.\n";
}
}

143
vn/web/app.php Executable file → Normal file
View File

@ -3,135 +3,52 @@
namespace Vn\Web;
require_once ('vn/lib/app.php');
require_once ('vn/lib/util.php');
use Vn\Lib;
use Vn\Lib\Locale;
use Vn\Db\Conn;
/**
* Thrown when user credentials could not be fetched.
**/
class SessionExpiredException extends Lib\UserException {}
/**
* Thrown when user credentials are invalid.
**/
class BadLoginException extends Lib\UserException {}
/**
* Thrown when client version is outdated.
**/
class OutdatedVersionException extends Lib\UserException {}
/**
* Main class for web applications.
*
* Format for $_REQUEST['srv'] variable:
* - [serviceName]:[requestDir]/[requestFile]
**/
abstract class App extends Lib\App
class App extends \Vn\Lib\App
{
protected $conn = NULL;
private $allowedServices =
[
'html',
'rest',
'json'
];
/**
* Starts the user session.
**/
function startSession ()
function run ()
{
if ($this->isHttps ())
ini_set ('session.cookie_secure', TRUE);
$this->init ();
ini_set ('session.hash_function', 'sha512');
session_start ();
// Setting the locale
$srv = empty ($_REQUEST['srv']) ? '' : $_REQUEST['srv'];
$explode = explode (':', $srv, 2);
if (isset ($_SERVER['HTTP_ACCEPT_LANGUAGE']))
if (!isset ($_SESSION['http_language'])
|| $_SESSION['http_language'] != $_SERVER['HTTP_ACCEPT_LANGUAGE'])
if (count ($explode) > 0)
$_REQUEST['service'] = $explode[0];
if (count ($explode) > 1)
$_REQUEST['method'] = $explode[1];
$service = empty ($_REQUEST['service']) ? 'html' : $_REQUEST['service'];
if (in_array ($service, $this->allowedServices, TRUE))
{
$_SESSION['http_language'] = $_SERVER['HTTP_ACCEPT_LANGUAGE'];
$regexp = '/([a-z]{1,4})(?:-[a-z]{1,4})?\s*(?:;\s*q\s*=\s*(?:1|0\.[0-9]+))?,?/i';
$includeFile = __DIR__."/$service-service.php";
require_once ($includeFile);
preg_match_all ($regexp, $_SERVER['HTTP_ACCEPT_LANGUAGE'], $languages);
foreach ($languages[1] as $lang)
if (stream_resolve_include_path ("locale/$lang"))
{
$_SESSION['lang'] = $lang;
break;
}
}
if (!isset ($_SESSION['lang']))
$_SESSION['lang'] = NULL;
Locale::set ($_SESSION['lang']);
// Registering the visit
if (!isset ($_COOKIE['PHPSESSID'])
|| isset ($_SESSION['access'])
|| isset ($_SESSION['skipVisit']))
return;
$agent = $_SERVER['HTTP_USER_AGENT'];
$browser = get_browser ($agent, TRUE);
if (isset ($browser['crawler']) && $browser['crawler'])
{
$_SESSION['skipVisit'] = TRUE;
return;
}
if (isset ($_SERVER['REMOTE_ADDR']))
$ip = ip2long ($_SERVER['REMOTE_ADDR']);
$sysConn = $this->getSysConn ();
$row = $sysConn->getRow (
'CALL visit_register (#, #, #, #, #, #, #, #, #)',
[
nullIf ($_COOKIE, 'vn_visit')
,nullIf ($browser, 'platform')
,nullIf ($browser, 'browser')
,nullIf ($browser, 'version')
,nullIf ($browser, 'javascript')
,nullIf ($browser, 'cookies')
,isset ($agent) ? $agent : NULL
,isset ($ip) && $ip ? $ip : NULL
,nullIf ($_SERVER, 'HTTP_REFERER')
]
);
if (isset ($row['access']))
{
setcookie ('vn_visit', $row['visit'], time () + 31536000); // 1 Year
$_SESSION['access'] = $row['access'];
$className = __NAMESPACE__ .'\\'. hyphenToCamelCase ($service, TRUE) .'Service';
$service = new $className ($this);
$service->run ();
}
else
$_SESSION['skipVisit'] = TRUE;
http_response_code (400);
}
/**
* Checks if the HTTP connection is secure.
*
* @return boolean Return %TRUE if its secure, %FALSE otherwise
**/
function isHttps ()
{
return isset ($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on';
}
/**
* Obtains the application version number. It is based on de last
* modification date of the main script.
**/
function getVersion ()
{
return (int) strftime ('%G%m%d%H%M%S',
filectime (__FILE__ /* $_SERVER['SCRIPT_FILENAME'] */));
}
/**
* Gets the configuration file name.
* Gets the configuration file name associated to the current vhost
* or the default config file if isn't defined a file for the vhost.
**/
function getConfigFile ()
{

View File

@ -2,21 +2,18 @@
namespace Vn\Web;
require_once (__DIR__.'/app.php');
require_once ('vn/lib/util.php');
require_once ('vn/lib/method.php');
require_once (__DIR__.'/service.php');
use Vn\Lib\Locale;
/**
* Base class for services that sends response as HTML format.
**/
class HtmlApp extends App
class HtmlService extends Service
{
function run ()
{
$this->init ();
$db = $this->getSysConn ();
$db = $this->app->getSysConn ();
if (!$this->isHttps ()
&& $db->getValue ('SELECT https FROM config'))
@ -29,8 +26,8 @@ class HtmlApp extends App
// Getting the requested page
if (!empty ($_GET['page']) && isHyphen ($_GET['page']))
$page = $_GET['page'];
if (!empty ($_REQUEST['method']) && isHyphen ($_REQUEST['method']))
$page = $_REQUEST['method'];
else
$page = 'main';
@ -77,7 +74,7 @@ class HtmlApp extends App
// Loading the requested page
$basePath = "{$this->methodDir}/$page";
$basePath = "./html/$page";
if (file_exists ($basePath))
{

View File

@ -2,7 +2,7 @@
namespace Vn\Web;
require_once (__DIR__.'/rest-app.php');
require_once (__DIR__.'/rest-service.php');
require_once (__DIR__.'/json-request.php');
require_once (__DIR__.'/json-reply.php');
@ -11,7 +11,7 @@ use Vn\Lib;
/**
* Base class for JSON application.
**/
class JsonApp extends RestApp
class JsonService extends RestService
{
private $warnings = NULL;
@ -21,7 +21,6 @@ class JsonApp extends RestApp
set_error_handler ([$this, 'errorHandler'], E_ALL);
set_exception_handler ([$this, 'exceptionHandler']);
$this->init ();
$this->startSession ();
// Checks the client version
@ -33,7 +32,8 @@ class JsonApp extends RestApp
&& $clientVersion < $this->getVersion ())
throw new OutdatedVersionException ();
$method = $this->loadMethod ($_REQUEST['method']);
$method = $this->app->loadMethod (
$_REQUEST['method'], __NAMESPACE__.'\JsonRequest', './rest');
$json = $method->run ();
$this->replyJson ($json);
}

View File

@ -2,7 +2,7 @@
namespace Vn\Web;
require_once (__DIR__.'/app.php');
require_once (__DIR__.'/service.php');
require_once (__DIR__.'/rest-request.php');
use Vn\Lib;
@ -10,7 +10,7 @@ use Vn\Lib;
/**
* Base class for REST application.
**/
class RestApp extends App
class RestService extends Service
{
function run ()
{
@ -18,10 +18,10 @@ class RestApp extends App
set_error_handler ([$this, 'errorHandler'], E_ALL);
set_exception_handler ([$this, 'exceptionHandler']);
$this->init ();
$this->startSession ();
$method = $this->loadMethod ($_REQUEST['method']);
$method = $this->app->loadMethod (
$_REQUEST['method'], __NAMESPACE__.'\RestRequest', './rest');
$method->run ();
}
@ -47,7 +47,7 @@ class RestApp extends App
if (isset ($_POST['guest']))
{
$sysConn = $this->getSysConn ();
$sysConn = $this->app->getSysConn ();
$row = $sysConn->getRow (
'SELECT guest_user, guest_pass FROM config');
@ -83,7 +83,7 @@ class RestApp extends App
throw new SessionExpiredException ();
try {
$db = $this->createConnection ($user, $password);
$db = $this->app->createConnection ($user, $password);
$db->query ('CALL user_session_start (#)', [session_id ()]);
$this->conn = $db;

139
vn/web/service.php Executable file
View File

@ -0,0 +1,139 @@
<?php
namespace Vn\Web;
require_once ('vn/lib/app.php');
use Vn\Lib;
use Vn\Lib\Locale;
use Vn\Db\Conn;
/**
* Thrown when user credentials could not be fetched.
**/
class SessionExpiredException extends Lib\UserException {}
/**
* Thrown when user credentials are invalid.
**/
class BadLoginException extends Lib\UserException {}
/**
* Thrown when client version is outdated.
**/
class OutdatedVersionException extends Lib\UserException {}
/**
* Main class for web applications.
**/
abstract class Service
{
protected $app;
protected $conn = NULL;
function __construct ($app)
{
$this->app = $app;
}
/**
* Starts the user session.
**/
function startSession ()
{
if ($this->isHttps ())
ini_set ('session.cookie_secure', TRUE);
ini_set ('session.hash_function', 'sha512');
session_start ();
// Setting the locale
if (isset ($_SERVER['HTTP_ACCEPT_LANGUAGE']))
if (!isset ($_SESSION['http_language'])
|| $_SESSION['http_language'] != $_SERVER['HTTP_ACCEPT_LANGUAGE'])
{
$_SESSION['http_language'] = $_SERVER['HTTP_ACCEPT_LANGUAGE'];
$regexp = '/([a-z]{1,4})(?:-[a-z]{1,4})?\s*(?:;\s*q\s*=\s*(?:1|0\.[0-9]+))?,?/i';
preg_match_all ($regexp, $_SERVER['HTTP_ACCEPT_LANGUAGE'], $languages);
foreach ($languages[1] as $lang)
if (stream_resolve_include_path ("locale/$lang"))
{
$_SESSION['lang'] = $lang;
break;
}
}
if (!isset ($_SESSION['lang']))
$_SESSION['lang'] = NULL;
Locale::set ($_SESSION['lang']);
// Registering the visit
if (!isset ($_COOKIE['PHPSESSID'])
|| isset ($_SESSION['access'])
|| isset ($_SESSION['skipVisit']))
return;
$agent = $_SERVER['HTTP_USER_AGENT'];
$browser = get_browser ($agent, TRUE);
if (isset ($browser['crawler']) && $browser['crawler'])
{
$_SESSION['skipVisit'] = TRUE;
return;
}
if (isset ($_SERVER['REMOTE_ADDR']))
$ip = ip2long ($_SERVER['REMOTE_ADDR']);
$db = $this->app->getSysConn ();
$row = $db->getRow (
'CALL visit_register (#, #, #, #, #, #, #, #, #)',
[
nullIf ($_COOKIE, 'vn_visit')
,nullIf ($browser, 'platform')
,nullIf ($browser, 'browser')
,nullIf ($browser, 'version')
,nullIf ($browser, 'javascript')
,nullIf ($browser, 'cookies')
,isset ($agent) ? $agent : NULL
,isset ($ip) && $ip ? $ip : NULL
,nullIf ($_SERVER, 'HTTP_REFERER')
]
);
if (isset ($row['access']))
{
setcookie ('vn_visit', $row['visit'], time () + 31536000); // 1 Year
$_SESSION['access'] = $row['access'];
}
else
$_SESSION['skipVisit'] = TRUE;
}
/**
* Checks if the HTTP connection is secure.
*
* @return boolean Return %TRUE if its secure, %FALSE otherwise
**/
function isHttps ()
{
return isset ($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on';
}
/**
* Obtains the application version number. It is based on de last
* modification date of the main script.
**/
function getVersion ()
{
return (int) strftime ('%G%m%d%H%M%S',
filectime (__FILE__ /* $_SERVER['SCRIPT_FILENAME'] */));
}
}
?>