From 1fdefaf6632b923522b4dd5147b6078d21219dd7 Mon Sep 17 00:00:00 2001 From: benoitpotier Date: Tue, 28 Mar 2017 17:25:23 +0200 Subject: [PATCH] add Scores repository --- src/Scores/Account/Access.php | 85 + src/Scores/Account/Category.php | 112 ++ src/Scores/Account/modeles/create.html | 67 + src/Scores/Account/modeles/password.html | 67 + src/Scores/Auth/Adapter/Db.php | 152 ++ src/Scores/Auth/Adapter/Ws.php | 189 +++ src/Scores/Bill/Article.php | 7 + src/Scores/Bill/Article/Category.php | 5 + src/Scores/Bill/Data.php | 17 + src/Scores/Bill/Pdf.php | 453 ++++++ src/Scores/Bill/Pdf/Table.php | 1 + src/Scores/Bill/logo.jpg | Bin 0 -> 4859 bytes src/Scores/Bill/logo.png | Bin 0 -> 12742 bytes src/Scores/Configure.php | 101 ++ src/Scores/Conso/Export.php | 95 ++ src/Scores/Conso/File.php | 135 ++ src/Scores/Conso/Flux.php | 66 + src/Scores/Conso/Logs.php | 358 +++++ src/Scores/Conso/Surveillances.php | 165 ++ src/Scores/Courrier/Generate.php | 373 +++++ src/Scores/Courrier/Model/modele.odt | Bin 0 -> 75650 bytes src/Scores/Courrier/Model/modele.pdf | Bin 0 -> 69588 bytes .../Courrier/Model/modeleLettreGreffe.odt | Bin 0 -> 79073 bytes src/Scores/Courrier/Pdf.php | 22 + src/Scores/Extract/Dict.php | 680 ++++++++ src/Scores/Locale/String.php | 88 ++ src/Scores/Locale/String/i18n-ascii.txt | 564 +++++++ src/Scores/Locale/String/special.txt | 2 + src/Scores/Logger/Sql.php | 66 + src/Scores/Mail/Method.php | 129 ++ src/Scores/Stat/Op.php | 237 +++ src/Scores/Surveillance/File.php | 90 ++ src/Scores/Upload/Handler.php | 1393 +++++++++++++++++ src/Scores/Validate/IpInNetwork.php | 632 ++++++++ src/Scores/Validate/IpInNetwork.txt | 39 + src/Scores/Wkhtml/Pdf.php | 53 + src/Scores/Ws/Discover.php | 84 + src/Scores/Ws/Doc.php | 181 +++ src/Scores/Ws/Exception.php | 4 + src/Scores/Ws/Form/GetIdentite.php | 23 + src/Scores/Ws/Server.php | 1102 +++++++++++++ src/Scores/Ws/Trigger.php | 131 ++ 42 files changed, 7968 insertions(+) create mode 100644 src/Scores/Account/Access.php create mode 100644 src/Scores/Account/Category.php create mode 100755 src/Scores/Account/modeles/create.html create mode 100755 src/Scores/Account/modeles/password.html create mode 100644 src/Scores/Auth/Adapter/Db.php create mode 100644 src/Scores/Auth/Adapter/Ws.php create mode 100644 src/Scores/Bill/Article.php create mode 100644 src/Scores/Bill/Article/Category.php create mode 100644 src/Scores/Bill/Data.php create mode 100644 src/Scores/Bill/Pdf.php create mode 100644 src/Scores/Bill/Pdf/Table.php create mode 100644 src/Scores/Bill/logo.jpg create mode 100644 src/Scores/Bill/logo.png create mode 100644 src/Scores/Configure.php create mode 100644 src/Scores/Conso/Export.php create mode 100644 src/Scores/Conso/File.php create mode 100644 src/Scores/Conso/Flux.php create mode 100644 src/Scores/Conso/Logs.php create mode 100644 src/Scores/Conso/Surveillances.php create mode 100644 src/Scores/Courrier/Generate.php create mode 100644 src/Scores/Courrier/Model/modele.odt create mode 100644 src/Scores/Courrier/Model/modele.pdf create mode 100644 src/Scores/Courrier/Model/modeleLettreGreffe.odt create mode 100644 src/Scores/Courrier/Pdf.php create mode 100644 src/Scores/Extract/Dict.php create mode 100644 src/Scores/Locale/String.php create mode 100644 src/Scores/Locale/String/i18n-ascii.txt create mode 100644 src/Scores/Locale/String/special.txt create mode 100644 src/Scores/Logger/Sql.php create mode 100644 src/Scores/Mail/Method.php create mode 100644 src/Scores/Stat/Op.php create mode 100644 src/Scores/Surveillance/File.php create mode 100644 src/Scores/Upload/Handler.php create mode 100644 src/Scores/Validate/IpInNetwork.php create mode 100644 src/Scores/Validate/IpInNetwork.txt create mode 100644 src/Scores/Wkhtml/Pdf.php create mode 100644 src/Scores/Ws/Discover.php create mode 100644 src/Scores/Ws/Doc.php create mode 100644 src/Scores/Ws/Exception.php create mode 100644 src/Scores/Ws/Form/GetIdentite.php create mode 100644 src/Scores/Ws/Server.php create mode 100644 src/Scores/Ws/Trigger.php diff --git a/src/Scores/Account/Access.php b/src/Scores/Account/Access.php new file mode 100644 index 0000000..678041f --- /dev/null +++ b/src/Scores/Account/Access.php @@ -0,0 +1,85 @@ + "Export des résultats de la recherche", + 'IPARI' => "Investigation par l'image IparI©", + 'HISTOBODACC' => "Historique des annonces bodacc", + 'INVESTIG' => "Investigation", + 'SEARCHENT' => "Recherche Entreprise", + 'SEARCHDIR' => "Recherche Dirigeant", + 'SEARCHACT' => "Recherche Actionnaire", + + //IDENTITE + 'IDENTITE' => "Fiche d'identité", + 'IDPROCOL' => 'Fiche procédure collective', + 'LIENS' => "Liens inter-entreprise", + 'ETABLISSEMENTS' => "Liste des établissements", + 'GROUPE' => "Informations et organigramme du groupe", + 'EVENINSEE' => 'Évènements INSEE', + 'AVISINSEE' => 'Avis de situation INSEE', + 'AVISRNCS' => 'Avis de situation RNCS', + 'RNVP' => "Normalisation postale", + + //DIRIGEANT + 'DIRIGEANTS' => "Liste des dirigeants", + 'DIRIGEANTSOP' => "Liste des dirigeants opérationnels", + + //FINANCE + 'SYNTHESE' => "Synthèse", + 'RATIOS' => "Ratios", + 'FLUX' => "Flux de trésorerie", + 'LIASSE' => "Liasse fiscale", + 'LIASSEXLS' => "Export des Liasses au format XLS", + 'UPLOADBILAN' => "Saisie de bilan", + 'BOURSE' => "Bourse & cotations", + 'BANQUE' => "Relations bancaires", + + //JURIDIQUE + 'ANNONCES' => "Annonces légales", + 'INFOSREG' => "Informations réglementée", + 'COMPETENCES' => "Compétences territoriales", + 'CONVENTIONS' => "Conventions collectives", + 'MARQUES' => "Marques déposées", + 'CONTENTIEUX' => "Contentieux Judiciaires", + + //EVALUATION + 'INDISCORE' => "indiScore©", + 'INDISCORE2' => "Rapport synthetique", + 'INDISCORE3' => "Rapport complet", + 'INDISCOREP' => "indiScore+", + 'INDISCORE2P' => "Rapport synthetique+", + 'INDISCORE3P' => "Rapport complet+", + 'VALORISATION' => "Valorisation", + 'SCORECSF' => "Score CSF", + 'ENQUETEC' => "Enquête commerciale", + 'AVISCREDIT' => "Avis de crédit personnalisé", + + //PIECES + 'KBIS' => "Extrait RCS", + 'ACTES' => "Pièces officielles", + 'PRIVILEGES' => "Privilèges", + + //SURVEILLANCES + 'SURVANNONCE' => "Surveillance des annonces légales", + 'SURVINSEE' => "Surveillance des événements INSEE", + 'SURVBILAN' => "Surveillance des bilans saisies (liasse fiscale)", + 'SURVSCORE' => "Surveillance des événements sur le score", + 'SURVACTES' => "Surveillance des pieces officielles (comptes annuels, actes)", + 'SURVDIRIGEANTS'=> "Surveillance des dirigeants", + 'SURVPAIEMENTS' => "Surveillance des paiements", + 'SURVLIENS' => "Surveillance des liens financiers", + 'SURVPRIV' => "Surveillance des privilèges", + + //OPTIONS + 'MONPROFIL' => "Mon profil", + 'EDITION' => "Mode Edition", + 'PORTEFEUILLE' => "Portefeuille", + 'SURVLISTE' => "Liste des surveillances", + + //DIVERS + 'INTERNATIONAL' => "Recherche Internationale", + 'BDF' => "Banque de France", + 'WORLDCHECK' => "World-Check Risk Intelligence", + +); diff --git a/src/Scores/Account/Category.php b/src/Scores/Account/Category.php new file mode 100644 index 0000000..badd2b1 --- /dev/null +++ b/src/Scores/Account/Category.php @@ -0,0 +1,112 @@ + array( + 'label' => "Recherche", + 'droits' => array( + 'RECHCSV', + 'IPARI', + 'HISTOBODACC', + 'INVESTIG', + 'SEARCHENT', + 'SEARCHDIR', + 'SEARCHACT' + ), + ), + 'IDENTITE' => array( + 'label' => "Identité", + 'droits' => array( + 'IDENTITE', + 'IDPROCOL', + 'LIENS', + 'ETABLISSEMENTS', + 'GROUPE', + 'EVENINSEE', + 'AVISINSEE', + 'AVISRNCS', + 'RNVP' + ), + ), + 'DIRIGEANT' => array( + 'label' => "Dirigeant", + 'droits' => array( + 'DIRIGEANTS', + 'DIRIGEANTSOP', + 'WORLDCHECK' + ), + ), + 'FINANCE' => array( + 'label' => 'Elements Financiers', + 'droits' => array( + 'SYNTHESE', + 'RATIOS', + 'FLUX', + 'LIASSE', + 'LIASSEXLS', + 'UPLOADBILAN', + 'BOURSE', + 'BANQUE' + ), + ), + 'JURIDIQUE' => array( + 'label' => 'Elements Juridiques', + 'droits' => array('ANNONCES', + 'INFOSREG', + 'COMPETENCES', + 'CONVENTIONS', + 'MARQUES', + 'CONTENTIEUX' + ), + ), + 'EVALUATION' => array( + 'label' => 'Evaluation', + 'droits' => array( + 'INDISCORE', + 'INDISCORE2', + 'INDISCORE3', + 'INDISCOREP', + 'INDISCORE2P', + 'INDISCORE3P', + 'VALORISATION', + 'ENQUETEC', + 'AVISCREDIT' + ), + ), + 'PIECES' => array( + 'label' => 'Pièces officielles', + 'droits' => array( + 'KBIS', + 'ACTES', + 'PRIVILEGES' + ), + ), + 'SURVEILLANCES' => array( + 'label' => 'Surveillances', + 'droits' => array( + 'SURVANNONCE', + 'SURVINSEE', + 'SURVBILAN', + 'SURVSCORE', + 'SURVACTES', + 'SURVDIRIGEANTS', + 'SURVPAIEMENTS', + 'SURVLIENS', + 'SURVPRIV', + ), + ), + 'OPTIONS' => array( + 'label' => 'Options', + 'droits' => array( + 'MONPROFIL', + 'SURVLISTE', + 'PORTEFEUILLE', + 'EDITION' + ), + ), + 'DIVERS' => array( + 'label' => 'Divers', + 'droits' => array( + 'INTERNATIONAL', + 'BDF' + ), + ), +); diff --git a/src/Scores/Account/modeles/create.html b/src/Scores/Account/modeles/create.html new file mode 100755 index 0000000..4f4d4c4 --- /dev/null +++ b/src/Scores/Account/modeles/create.html @@ -0,0 +1,67 @@ +
+

+Scores & Décisions - Paramètres d'accès

+ + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + +
+
Interface
+
+ http://extranet.scores-decisions.com + - Cliquer sur ce lien et enregistrer le dans votre navigateur +
+
Login
+
+
+
{{Login}} + - Votre Identifiant
+
+
+
Mot de passe
+
+
+
{{Password}} + - respecter la casse des caractères
+
+
+
Date d'ouverture de compte
+
{{DateHeure}} + Paris +
+
+
+

Vous recevez ce message à l'adresse {{Email}}, +suite à l'ouverture d'un contrat pour une prestation chez Scores & Décisions. +http://www.scores-decisions.com.
+L’équipe Support est à votre disposition pour +toute question. +

+
+
\ No newline at end of file diff --git a/src/Scores/Account/modeles/password.html b/src/Scores/Account/modeles/password.html new file mode 100755 index 0000000..738815a --- /dev/null +++ b/src/Scores/Account/modeles/password.html @@ -0,0 +1,67 @@ +
+

+Scores & Décisions - Modification de vos paramètres d'accès

+ + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + +
+
Interface
+
+ http://extranet.scores-decisions.com + - Cliquer sur ce lien et enregistrer le dans votre navigateur +
+
Login
+
+
+
{{Login}} + - Votre Identifiant
+
+
+
Mot de passe
+
+
+
{{Password}} + - respecter la casse des caractères
+
+
+
Date de modification
+
{{DateHeure}} + Paris +
+
+
+

Vous recevez ce message à l'adresse {{Email}}, +suite à une modification de votre accès chez Scores & Décisions. +http://www.scores-decisions.com.
+L’équipe Support est à votre disposition pour +toute question. +

+
+
\ No newline at end of file diff --git a/src/Scores/Auth/Adapter/Db.php b/src/Scores/Auth/Adapter/Db.php new file mode 100644 index 0000000..0ac61cb --- /dev/null +++ b/src/Scores/Auth/Adapter/Db.php @@ -0,0 +1,152 @@ +_username = $username; + $this->_password = $password; + $this->_hash = md5($username.'|'.$password); + $this->checkWs = $checkWs; + + $this->conn = Zend_Registry::get('doctrine'); + + if (Zend_Registry::isRegistered('logger')) { + $this->logger = Zend_Registry::get('logger'); + } + } + + /** + * Limit access to only client IDs + * @param array $id + */ + public function limitClient($id = null) + { + if (is_array($id) && count($id) > 0) { + $this->clients = $id; + } + } + + /** + * Override the timeout + * @param integer $seconds + */ + public function setTimeout($seconds = null) + { + if ($seconds === null) { + return; + } + + $this->_timeout = $seconds; + } + + /** + * (non-PHPdoc) + * @see Zend_Auth_Adapter_Interface::authenticate() + */ + public function authenticate() + { + try { + $qb = $this->conn->createQueryBuilder(); + $qb->select(array('u.idClient', 'u.id', 'u.login', 'u.password', 'c.timeout')) + ->from('sdv1.utilisateurs', 'u') + ->join('u', 'sdv1.clients', 'c', 'u.idClient = c.id') + ->where("u.login=:login")->setParameter('login', $this->_username) + ->andWhere("u.actif=1") + ->andWhere("u.deleted=0") + ->andWhere("c.actif='Oui'"); + if (count($this->clients) > 0) { + $qb->andWhere('u.idClient IN('.join(',', $this->clients).')'); + } + + if ($this->checkWs) { + $qb->andWhere('u.accesWS=1'); + } + + $stmt = $qb->execute(); + } catch (\Doctrine\DBAL\DBALException $e) { + if ($this->logger !== null) { + $this->logger->error($e->getMessage()); + } + } + + $identity = new stdClass(); + $identity->username = $this->_username; + $identity->hash = $this->_hash; + + if ($stmt->rowCount() == 0) { + return new Zend_Auth_Result(Zend_Auth_Result::FAILURE_IDENTITY_NOT_FOUND, $identity, + array("Identifiant ou mot de passe invalid")); + } else { + $result = $stmt->fetch(PDO::FETCH_OBJ); + if ($this->_password == $result->password + || $this->_password == md5($result->login.'|'.$result->password)) { + + /** + * Date de debut de compte + */ + if (!empty($result->dateDebutCompte) && $result->dateDebutCompte!='0000-00-00') { + $today = mktime(0, 0, 0, date('m'), date('d'), date('Y')); + $dateDebutCompte = mktime(0, 0, 0, substr($result->dateDebutCompte, 5, 2), + substr($result->dateDebutCompte, 8, 2), substr($result->dateDebutCompte, 0, 4)); + if ($today < $dateDebutCompte) { + return new Zend_Auth_Result(Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID, $identity, + array("Date de validité dépassé")); + } + } + + /** + * Date de fin de compte + */ + if (!empty($result->dateFinCompte) && $result->dateFinCompte!='0000-00-00') { + $today = mktime(0, 0, 0, date('m'), date('d'), date('Y')); + $dateFinCompte = mktime(0, 0, 0, substr($result->dateFinCompte, 5, 2), + substr($result->dateFinCompte, 8, 2), substr($result->dateFinCompte, 0, 4)); + if ($today > $dateFinCompte) { + return new Zend_Auth_Result(Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID, $identity, + array("Date de validité dépassé")); + } + } + + $identity->id = $result->id; + $identity->idClient = $result->idClient; + $timeout = (!empty($result->timeout)) ? $result->timeout : $this->_timeout; + $identity->timeout = $timeout; + $identity->time = time() + $timeout; + return new Zend_Auth_Result(Zend_Auth_Result::SUCCESS, $identity); + } else { + return new Zend_Auth_Result(Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID, $identity, + array("Identification impossible")); + } + } + } +} diff --git a/src/Scores/Auth/Adapter/Ws.php b/src/Scores/Auth/Adapter/Ws.php new file mode 100644 index 0000000..98f482d --- /dev/null +++ b/src/Scores/Auth/Adapter/Ws.php @@ -0,0 +1,189 @@ +_username = $username; + $this->_password = $password; + + if ($mode == 'hach') { + $this->_checkHach = true; + } + + if ($mode == 'iponly') { + $ip = $_SERVER['REMOTE_ADDR']; + if (isset($_SERVER['HTTP_X_FORWARDED_FOR']) && in_array($ip, $this->listProxyIp)) { + $ip = $_SERVER['HTTP_X_FORWARDED_FOR']; + } + $this->_password = 'iponly:'.$ip; + $this->_checkIp = true; + } + } + + /** + * (non-PHPdoc) + * @see Zend_Auth_Adapter_Interface::authenticate() + */ + public function authenticate() + { + $ip = $_SERVER['REMOTE_ADDR']; + if (isset($_SERVER['HTTP_X_FORWARDED_FOR']) && in_array($ip, $this->listProxyIp)) { + $ip = $_SERVER['HTTP_X_FORWARDED_FOR']; + } + + $ws = new Scores_Ws_Client('gestion', '0.3'); + $ws->setHttpLogin($this->_username); + $ws->setHttpPassword($this->_password); + $adressIp = $_SERVER['REMOTE_ADDR']; + $parameters = new stdClass(); + $parameters->login = $this->_username; + $parameters->ipUtilisateur = $ip; + $parameters->from = 'auth'; + $InfosLogin = $ws->getInfosLogin($parameters); + + // --- Renvoi + if (is_string($InfosLogin) || $InfosLogin->error->errnum != 0) { + $message = $InfosLogin; + return new Zend_Auth_Result(Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID, $identity, array($message)); + } + // --- Assignation identity + elseif ($InfosLogin !== false && !empty($InfosLogin->result->login)) { + $identity = new stdClass(); + if ($this->_checkIp || $this->_checkHach) { + Zend_Registry::get('firebug')->info("IN"); + $identity->password = $this->_password; + } else { + $identity->password = md5($InfosLogin->result->login.'|'.$this->_password); + } + Zend_Registry::get('firebug')->info($identity->password); + $identity->username = $InfosLogin->result->login; + $identity->email = $InfosLogin->result->email; + $identity->profil = $InfosLogin->result->profil; + $identity->pref = $InfosLogin->result->pref; + $identity->droits = $InfosLogin->result->droits; + $identity->droitsClients = $InfosLogin->result->droitsClients; + $identity->nom = $InfosLogin->result->nom; + $identity->prenom = $InfosLogin->result->prenom; + $identity->tel = $InfosLogin->result->tel; + $identity->fax = $InfosLogin->result->fax; + $identity->mobile = $InfosLogin->result->mobile; + $identity->id = $InfosLogin->result->id; + $identity->idClient = $InfosLogin->result->idClient; + $identity->reference = $InfosLogin->result->reference; + $identity->nbReponses = $InfosLogin->result->nbReponses; + $identity->typeScore = $InfosLogin->result->typeScore; + $identity->dateValidation = $InfosLogin->result->dateValidation; + $identity->nombreConnexions = $InfosLogin->result->nombreConnexions; + $identity->dateDerniereConnexion = $InfosLogin->result->dateDerniereConnexion; + $identity->dateDebutCompte = $InfosLogin->result->dateDebutCompte; + $identity->dateFinCompte = $InfosLogin->result->dateFinCompte; + $identity->acceptationCGU = $InfosLogin->result->acceptationCGU; + $identity->ip = $ip; + $identity->version = $InfosLogin->result->version; + $identity->modeEdition = false; + + $timeout = (!empty($InfosLogin->result->timeout)) ? $InfosLogin->result->timeout : $this->_timeout; + $identity->timeout = $timeout; + $identity->time = time() + $timeout; + $lang = in_array($InfosLogin->result->lang, array('fr', 'en')) ? $InfosLogin->result->lang : 'fr'; + $identity->lang = $lang; + $identity->langtmp = $lang; + + // --- Adresse Ip interdites + $ipInterdites = array( + '81.252.88.0-81.252.88.7', // CTE D AGGLOMERATION DE SOPHIA + '195.200.187.163', // PacWan + '213.11.81.41', // Verizon France SAS + '83.206.171.252', // FR-BASE-D-INFORMATIONS-LEGALES-BI + '81.255.32.139', + '212.155.191.100-212.155.191.199', // Satair A/S + '212.37.196.156', // GENERALE-MULTIMEDIA-SUD + '80.245.60.121', // Planete Marseille - Mailclub + '213.246.57.101', // IKOULA + '193.104.158.0-193.104.158.255', // Altares.fr + '195.6.3.0-195.6.3.255', // ORT + '217.144.112.0-217.144.116.63', // Coface + ); + + // --- Validation IP + $overallIpValidate = false; + foreach ($ipInterdites as $filtre) { + if (strpos($filtre, '*')) { + $filtre = str_replace('*', '0', $filtre) . '-' . str_replace('*', '255', $filtre); + } + // Is it a range ? + if (strpos($filtre, '-')) { + $validateIp = new Scores_Validate_IpInNetwork(); + $validateIp->setNetworkNotation($filtre); + $overallIpValidate = $validateIp->isValid($ipToValidate); + } + // Ip only + else { + if ($filtre === $ipToValidate) { + $overallIpValidate = true; + } + } + // Break foreach + if ($overallIpValidate === true) { + break; + } + } + + // Exit with error + if ($overallIpValidate === false) { + return new Zend_Auth_Result(Zend_Auth_Result::FAILURE_UNCATEGORIZED, $identity); + } + + // --- OK connecté + $this->_username = $identity->username; + $this->_password = $identity->password; + return new Zend_Auth_Result(Zend_Auth_Result::SUCCESS, $identity); + } else { + return new Zend_Auth_Result(Zend_Auth_Result::FAILURE_UNCATEGORIZED, $identity, array("Identification impossible")); + } + } +} diff --git a/src/Scores/Bill/Article.php b/src/Scores/Bill/Article.php new file mode 100644 index 0000000..f6aa708 --- /dev/null +++ b/src/Scores/Bill/Article.php @@ -0,0 +1,7 @@ + "Extranet", + 'webservice' => "WebService", +); \ No newline at end of file diff --git a/src/Scores/Bill/Data.php b/src/Scores/Bill/Data.php new file mode 100644 index 0000000..15591c3 --- /dev/null +++ b/src/Scores/Bill/Data.php @@ -0,0 +1,17 @@ +Image($image_file, PDF_MARGIN_LEFT, 0, 50, '', 'JPG', '', 'T', false, 300, 'C', false, false, 0, false, false, false); + // Set font + $this->SetFont('helvetica', 'B', 15); + $this->SetAbsXY(PDF_MARGIN_LEFT, PDF_MARGIN_HEADER); + $this->Cell(0, 15, '', 'B', false, 'C', 0, '', 0, false, 'M', 'M'); + } + + public function Footer() + { + $cur_y = $this->y; + $this->SetTextColorArray($this->footer_text_color); + //set style for cell border + $line_width = (0.85 / $this->k); + $this->SetLineStyle(array('width' => $line_width, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => $this->footer_line_color)); + + $w_page = isset($this->l['w_page']) ? $this->l['w_page'].' ' : ''; + if (empty($this->pagegroups)) { + $pagenumtxt = $w_page.$this->getAliasNumPage().' / '.$this->getAliasNbPages(); + } else { + $pagenumtxt = $w_page.$this->getPageNumGroupAlias().' / '.$this->getPageGroupAlias(); + } + $this->SetY($cur_y); + + // Print legal + $this->Cell(0, 10, "Société anonyme par actions simplifiée au capital de 618 450,00 Euros - SIRET : 494 967 938 00056 RCS VERSAILLES B 494967938 - N.I.I: FR 84 494967938", 'T', 1, 'C'); + + // Print page number + $this->SetX($this->original_lMargin); + $this->Cell(0, 0, $this->getAliasRightShift().$pagenumtxt, 0, 0, 'R'); + } + + public function setData($id) + { + // --- Lecture des paramètres de la facturation + $factureM = new Application_Model_FacturationFacture(); + $factureSql = $factureM->select()->where('id=?', $id); + $factureResult = $factureM->fetchRow($factureSql); + + if ($factureResult->type == 'avoir') { + $this->Title = 'Avoir'; + } + switch($factureResult->paiement) { + case 'virement': + $this->ModePaiement = 'Virement'; + break; + case 'cheque': + $this->ModePaiement = 'Cheque'; + break; + case 'none': + $this->ModePaiement = ''; + break; + } + $this->Num = $factureResult->num; + $this->Label = $factureResult->label; + $this->Date = substr($factureResult->date,8,2).'/'.substr($factureResult->date,5,2).'/'.substr($factureResult->date,0,4); + $this->DateDue = substr($factureResult->dateDue,8,2).'/'.substr($factureResult->dateDue,5,2).'/'.substr($factureResult->dateDue,0,4); + $this->ClientNum = $factureResult->clientCode; + $this->DatePeriodBegin = substr($factureResult->periodBegin,8,2).'/'.substr($factureResult->periodBegin,5,2).'/'.substr($factureResult->periodBegin,0,4); + $this->DatePeriodEnd = substr($factureResult->periodEnd,8,2).'/'.substr($factureResult->periodEnd,5,2).'/'.substr($factureResult->periodEnd,0,4); + + /* + $adresseM = new Application_Model_FacturationFactureZoneclient(); + $adresseSql = $adresseM->select()->where('factId=?', $id); + */ + + // --- Articles à facturer + $lineM = new Application_Model_FacturationFactureLine(); + $lineSql = $lineM->select()->where('factId=?', $id)->order('num ASC'); + $lineResult = $lineM->fetchAll($lineSql); + $data = array(); + foreach ($lineResult as $l) { + $data[] = array($l->code, $l->zonetxt, $l->qte, $l->montantUnit, $l->montantLine, $l->tva); + } + $this->Line = $data; + + // --- Calcul + if (count($lineResult) > 0) { + foreach($lineResult as $l) { + $lineTVA = new stdClass(); + if (array_key_exists($l->tva, $this->TauxTVA)) { + $old = $this->TauxTVA[$l->tva]; + $lineTVA->Base = $l->montantLine + $old->Base; + $lineTVA->Mt = $lineTVA->Base * ($l->tva / 100); + } else { + $lineTVA->Base = $l->montantLine; + } + $lineTVA->Mt = $lineTVA->Base * ($l->tva / 100); + $this->TauxTVA[$l->tva] = $lineTVA; + $this->TotalHT+= $l->montantLine; + $this->TotalTTC+= $l->montantLine * (1 + $l->tva / 100); + $this->TotalTVA = $this->TotalTTC - $this->TotalHT; + } + } + } + + public function displayLines() + { + // column titles + $header = array('Code', 'Description', 'Quantité', 'P.U. HT', 'Total HT', 'Tx TVA'); + $w = array(30, 86, 16, 16, 16, 16); + + // Colors, line width and bold font + $this->SetFillColor(200, 200, 200); + $this->SetTextColor(0); + $this->SetDrawColor(0, 0, 0); + //$this->SetLineWidth(0.3); + $this->SetFont('', 'B', 10); + // Header + $num = count($header); + for($i = 0; $i < $num; ++$i) { + $this->Cell($w[$i], 7, $header[$i], 1, 0, 'C', 1); + } + $this->Ln(); + // Color and font restoration + $this->SetFillColor(224, 235, 255); + $this->SetTextColor(0); + $this->SetFont(''); + // Data + $fill = 0; + foreach($this->Line as $row) { + // Label cell + //$this->Cell($w[1], 6, $row[1], 'LR', 0, 'L', $fill, '', 0, true); + $this->SetAbsX(PDF_MARGIN_LEFT + $w[0]); + $nbLine = $this->MultiCell($w[1], 6, $row[1], 'LR', 'L', $fill, 0); + // Other cells + $this->SetAbsX(PDF_MARGIN_LEFT); + $this->Cell($w[0], 6 * $nbLine, $row[0], 'LR', 0, 'L', $fill, '', 0, false, 'T', 'T'); + $this->SetAbsX(PDF_MARGIN_LEFT + $w[0] + $w[1]); + $this->Cell($w[2], 6 * $nbLine, number_format($row[2], 2, ',', ' '), 'LR', 0, 'R', $fill, '', 0, false, 'T', 'T'); + $this->Cell($w[3], 6 * $nbLine, number_format($row[3], 2, ',', ' '), 'LR', 0, 'R', $fill, '', 0, false, 'T', 'T'); + $this->Cell($w[4], 6 * $nbLine, number_format($row[4], 2, ',', ' '), 'LR', 0, 'R', $fill, '', 0, false, 'T', 'T'); + $this->Cell($w[5], 6 * $nbLine, number_format($row[5], 2, ',', ' '), 'LR', 0, 'R', $fill, '', 0, false, 'T', 'T'); + $this->Ln(); + $fill=!$fill; + } + $this->Cell(array_sum($w), 0, '', 'T'); + $this->Ln(); + } + + public function displayResumeTaxe() + { + $this->posY = $this->y; + + $header = array('Tx TVA', 'Base', 'Montant TVA'); + $data = array(); + foreach ($this->TauxTVA as $t => $d) { + $data[] = array($t, $d->Base, $d->Mt); + } + $widthColTotal = $this->getPageWidth() - PDF_MARGIN_LEFT - PDF_MARGIN_RIGHT - 80; + $widthCol = $widthColTotal / 3; + $w = array($widthCol, $widthCol, $widthCol); + + // Colors, line width and bold font + $this->SetFillColor(200, 200, 200); + $this->SetTextColor(0); + $this->SetDrawColor(0, 0, 0); + //$this->SetLineWidth(0.3); + $this->SetFont('', 'B', 8); + // Header + $num = count($header); + for($i = 0; $i < $num; ++$i) { + $this->Cell($w[$i], 6, $header[$i], 1, 0, 'C', 1); + } + $this->Ln(); + // Color and font restoration + $this->SetFillColor(224, 235, 255); + $this->SetTextColor(0); + $this->SetFont(''); + // Data + $fill = 0; + foreach($data as $row) { + for($i = 0; $i < $num; ++$i) { + $this->Cell($w[$i], 6, number_format($row[$i], 2, ',', ' '), 'LR', 0, 'R', $fill); + } + $this->Ln(); + $fill=!$fill; + } + $this->Cell(array_sum($w), 0, '', 'T'); + $this->Ln(); + } + + public function displayTotal() + { + $this->setY($this->posY); + + $header = array('Total HT', 'Total TVA', 'Total TTC', 'Net à payer (en euros)'); + $data = array($this->TotalHT, $this->TotalTVA, $this->TotalTTC, $this->TotalTTC); + $w = array(45, 45, 45, 45); + $maxPosX = $this->getPageWidth() - PDF_MARGIN_RIGHT; + + $num = count($header); + for($i = 0; $i < $num; ++$i) { + $this->SetAbsX($maxPosX - 45 - 30); + // Header - Colors, line width and bold font + $this->SetFillColor(200, 200, 200); + $this->SetTextColor(0); + $this->SetDrawColor(0, 0, 0); + $this->SetLineWidth(0.3); + $this->SetFont('', 'B', 10); + $this->Cell(45, 7, $header[$i], 1, 0, 'C', 1); + + // Data - Color and font restoration + $this->SetFillColor(224, 235, 255); + $this->SetTextColor(0); + $this->SetFont(''); + //$this->SetAbsX($maxPosX - $x); + $this->Cell(30, 7, number_format($data[$i], 2, ',', ' '), 1, 0, 'R', 0); + + $this->Ln(); + } + } + + public function displayPaiement() + { + $this->SetFont('', 'B', 8); + $w = $this->getPageWidth() - PDF_MARGIN_LEFT - PDF_MARGIN_RIGHT - 80; + $this->Cell($w, 0, "Mode de paiement : " . $this->ModePaiement, 'LTR', 1); + $this->Cell($w, 0, "Date d'échéance : " . $this->DateDue, 'LBR', 1); + } + + public function displayIBAN() + { + $header = array('Code Banque', 'Code Guichet', 'N° Compte', 'Clé'); + $data = array('42559', '00072', '21009306208', '91'); + + $widthColTotal = $this->getPageWidth() - PDF_MARGIN_LEFT - PDF_MARGIN_RIGHT - 80; + $widthCol = $widthColTotal / count($header); + + $this->SetFont(''); + $this->Ln(); + // Header + $num = count($header); + for($i = 0; $i < $num; ++$i) { + $this->Cell($widthCol, 6, $header[$i], 1, 0, 'C', 0); + } + $this->Ln(); + // Data + $fill = 0; + for($i = 0; $i < $num; ++$i) { + $this->Cell($widthCol, 6, $data[$i], 'LTRB', 0, 'C', $fill); + } + $this->Ln(); + + $w = $this->getPageWidth() - PDF_MARGIN_LEFT - PDF_MARGIN_RIGHT - 80; + $this->Cell($w, 0, "Code IBAN : FR76 4255 9000 7221 0093 0620 891", 'LTR', 1); + $this->Cell($w, 0, "BIC : CCOPFRPPXXX - Domiciliation : CREDITCOOP PARIS POMMIER", 'LBR', 1); + } + + public function displayFooter() + { + $this->Ln(); + $this->SetFont('', '', 8); + $maxPosX = $this->getPageWidth() - PDF_MARGIN_RIGHT; + $this->Cell($this->getPageWidth() - PDF_MARGIN_LEFT - PDF_MARGIN_RIGHT, 0, '', 'T'); + $this->Ln(); + // Info + $this->Cell(20, 0, "Escompte pour paiement anticipé : Néant", 0, 1, 'L', 0, '', 0, false, 'T', 'M'); + $this->Cell(20, 0, "Pénalités de retard ; 1,5 fois le taux de l'interêt légal", 0, 1, 'L', 0, '', 0, false, 'T', 'M'); + $this->Cell(20, 0, "Frais de recouvrement : pénalité forfaitaire fixée à 10% des sommes dues", 0, 1, 'L', 0, '', 0, false, 'T', 'M'); + + } + + public function compile($id) + { + $this->setPageUnit('mm'); + $this->setPageFormat('A4', 'P'); + + $this->SetAuthor('SCORES ET DECISIONS'); + + $this->setData($id); + + $this->SetTitle($this->Title); + $this->SetSubject($this->Title); + + // set default header data + //$this->SetHeaderData('', 200, "FACTURE", "Scores & Décisions"); + + // set header and footer fonts + $this->setHeaderFont(Array(PDF_FONT_NAME_MAIN, '', PDF_FONT_SIZE_MAIN)); + $this->setFooterFont(Array(PDF_FONT_NAME_DATA, '', PDF_FONT_SIZE_DATA)); + + // set default monospaced font + $this->SetDefaultMonospacedFont(PDF_FONT_MONOSPACED); + + // set margins + $this->SetMargins(PDF_MARGIN_LEFT, 20, PDF_MARGIN_RIGHT); + $this->SetHeaderMargin(PDF_MARGIN_HEADER); + $this->SetFooterMargin(PDF_MARGIN_FOOTER); + + // set auto page breaks + $this->SetAutoPageBreak(TRUE, PDF_MARGIN_BOTTOM); + + // set image scale factor + $this->setImageScale(PDF_IMAGE_SCALE_RATIO); + + // add a page + $this->AddPage(); + + // set font + $this->SetFont('times', '', 16); + + $maxPosX = $this->getPageWidth() - PDF_MARGIN_RIGHT; + $minPosX = PDF_MARGIN_LEFT; + $maxWidth = $this->getPageWidth() - PDF_MARGIN_RIGHT - PDF_MARGIN_LEFT; + + $this->Cell($maxWidth - 115, 15, strtoupper($this->Title), 0, false, 'C', 0, '', 0, false, 'M', 'M'); + + $this->SetAbsY(15); + + $this->SetFont('times', '', 10); + + // Infos Facture + $this->SetFillColor(200, 200, 200); + $this->SetTextColor(0); + $this->SetDrawColor(0, 0, 0); + //$this->SetLineWidth(0.3); + $this->SetFont('', 'B'); + // Header + $header = array('N°', 'Date', 'Code client'); + $w = array(40, 35, 40); + $num = count($header); + $x = 0; + for($i = 0; $i < $num; ++$i) { + $x+= $w[$num-($i+1)]; + $this->SetAbsX($maxPosX - $x); + $this->Cell($w[$num-($i+1)], 7, $header[$num-($i+1)], 1, 0, 'C', 1); + } + $this->Ln(); + // Data + $this->SetFillColor(255, 255, 255); + $data = array($this->Num, $this->Date, $this->ClientNum); + $num = count($data); + $x = 0; + for($i = 0; $i < $num; ++$i) { + $x+= $w[$num-($i+1)]; + $this->SetAbsX($maxPosX - $x); + $this->Cell($w[$num-($i+1)], 7, $data[$num-($i+1)], 1, 0, 'C', 1); + } + + $this->Ln(); + + $infoClientY = $this->GetY(); + + // set color for background + $this->SetFillColor(255, 255, 255); + + // Infos Client + $w = 90; + $this->SetFont('', 'B'); + $this->SetAbsXY($maxPosX - $w, $infoClientY + 5); + $this->Cell($w, 0, "Adresse de facturation", '', 1, '', false, '', 0, false, 'T', 'M'); + $this->SetFont('', ''); + $this->SetAbsX($maxPosX - $w); + $this->Cell($w, 0, "L1", '', 1, '', false, '', 0, false, 'T', 'M'); + $this->SetAbsX($maxPosX - $w); + $this->Cell($w, 0, "L2", '', 1, '', false, '', 0, false, 'T', 'M'); + $this->SetAbsX($maxPosX - $w); + $this->Cell($w, 0, "L3", '', 1, '', false, '', 0, false, 'T', 'M'); + $this->SetAbsX($maxPosX - $w); + $this->Cell($w, 0, "L4", '', 1, '', false, '', 0, false, 'T', 'M'); + $this->SetAbsX($maxPosX - $w); + $this->Cell($w, 0, "L5", '', 1, '', false, '', 0, false, 'T', 'M'); + $this->SetAbsX($maxPosX - $w); + $this->Cell($w, 0, "L6", '', 1, '', false, '', 0, false, 'T', 'M'); + $this->SetAbsX($maxPosX - $w); + $this->Cell($w, 0, "L7", '', 1, '', false, '', 0, false, 'T', 'M'); + $this->SetAbsX($maxPosX - $w); + $this->Cell($w, 0, "L8", '', 1, '', false, '', 0, false, 'T', 'M'); + + $infoClientEndY = $this->GetY(); + + // Infos SCORES + $w = 90; + $this->SetAbsY($infoClientY + 10); + $this->Cell($w, 0, "SCORES ET DECISIONS SAS", 0, 1, '', false, '', 0, false, 'T', 'M'); + $this->SetFont('', ''); + $this->Cell($w, 0, "1 RUE DE CLAIREFONTAINE", 0, 1, '', false, '', 0, false, 'T', 'M'); + $this->Cell($w, 0, "78120 RAMBOUILLET", 0, 1, '', false, '', 0, false, 'T', 'M'); + $this->Cell($w, 0, "compta@scores-decisions.com", 0, 1, '', false, '', 0, false, 'T', 'M'); + $this->Cell($w, 0, "Tél : 01 75 43 80 10 - Fax : 01 75 43 85 74", 0, 1, '', false, '', 0, false, 'T', 'M'); + $this->Ln(); + + + $this->SetAbsY($infoClientEndY); + $this->SetFont('', 'B', 12); + $this->Cell(20, 0, "Période du " . $this->DatePeriodBegin . " au " . $this->DatePeriodEnd, 0, 1); + $this->SetFont('', '', 12); + $this->Cell(20, 0, "Objet : " . $this->Label, 0, 1); + $this->Ln(); + + // Create table article + $this->displayLines(); + + // Create taxe Resume + $this->displayResumeTaxe(); + + $this->displayPaiement(); + + $this->displayIBAN(); + + $this->displayFooter(); + + //Create total + $this->displayTotal(); + + + // move pointer to last page + $this->lastPage(); + + // --------------------------------------------------------- + + //Close and output PDF document + $this->Output(APPLICATION_PATH . '/../testfacture.pdf', 'F'); + } +} \ No newline at end of file diff --git a/src/Scores/Bill/Pdf/Table.php b/src/Scores/Bill/Pdf/Table.php new file mode 100644 index 0000000..b3d9bbc --- /dev/null +++ b/src/Scores/Bill/Pdf/Table.php @@ -0,0 +1 @@ +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 literal 0 HcmV?d00001 diff --git a/src/Scores/Bill/logo.png b/src/Scores/Bill/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..5f262969656fb4d21b125f9e736b981aafd1ac1f GIT binary patch literal 12742 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 M07*qoM6N<$f)j)R{r~^~ literal 0 HcmV?d00001 diff --git a/src/Scores/Configure.php b/src/Scores/Configure.php new file mode 100644 index 0000000..cbdaa77 --- /dev/null +++ b/src/Scores/Configure.php @@ -0,0 +1,101 @@ +readConfig(); + $this->_defineDb(); + $this->_definePath(); + $this->_defineSphinx(); + $this->_defineMail(); + } + + /** + * Read config application.ini + */ + protected function readConfig() + { + if ( Zend_Registry::isRegistered('config') ) { + $c = Zend_Registry::get('config'); + $this->profil = $c->profil; + } else { + $c = new Zend_Config_Ini(APPLICATION_PATH . '/configs/application.ini', 'production'); + $this->profil = $c->profil; + } + } + + protected function _defineDb() + { + $c = Zend_Registry::get('config'); + if ( $c->resources->db ) { + define('MYSQL_HOST', $c->resources->db->params->host); + define('MYSQL_USER', $c->resources->db->params->username); + define('MYSQL_PASS', $c->resources->db->params->password); + define('MYSQL_DEFAULT_DB', 'jo'); + define('MYSQL_SQL_LOG', 'NONE'); + } + } + + + protected function _definePath() + { + //Use of realpath + + define('BODACC_LOCAL_DIR' , '/home/data/bodacc/'); + define('JAL_LOCAL_DIR' , '/home/data/jal/'); + define('HUGIN_LOCAL_DIR' , '/home/data/infosreg/hugin/'); + define('ACTUSNEWS_LOCAL_DIR' , '/home/data/infosreg/actusnews/'); + define('DIRELEASE_LOCAL_DIR' , '/home/data/infosreg/direlease/'); + define('LESECHOS_LOCAL_DIR' , '/home/data/infosreg/lesechos/'); + define('BUSINESSWIRE_LOCAL_DIR_INCOMING' , '/home/data/ftp/businesswire/'); + define('BUSINESSWIRE_LOCAL_DIR' , '/home/data/infosreg/businesswire/'); + + define('DOC_WEB_LOCAL' , $this->profil->path->files.'/'); + define('DOC_WEB_URL' , '/fichier/'); + define('LOG_PATH' , $this->profil->path->shared.'/log'); + } + + protected function _defineSphinx() + { + // Entreprise + define('SPHINX_ENT_HOST', $this->profil->sphinx->ent->host); + define('SPHINX_ENT_PORT', intval($this->profil->sphinx->ent->port)); + define('SPHINX_ENT_VERSION', $this->profil->sphinx->ent->version); + + // Dirigeants + define('SPHINX_DIR_HOST', $this->profil->sphinx->dir->host); + define('SPHINX_DIR_PORT', intval($this->profil->sphinx->dir->port)); + define('SPHINX_DIR_VERSION', $this->profil->sphinx->dir->version); + + // Historique + define('SPHINX_HISTO_HOST', $this->profil->sphinx->histo->host); + define('SPHINX_HISTO_PORT', intval($this->profil->sphinx->histo->port)); + define('SPHINX_HISTO_VERSION', $this->profil->sphinx->histo->version); + + // Actionnaire + define('SPHINX_ACT_HOST', $this->profil->sphinx->act->host); + define('SPHINX_ACT_PORT', intval($this->profil->sphinx->act->port)); + define('SPHINX_ACT_VERSION', $this->profil->sphinx->act->version); + + //Old + define('SPHINX_HOST', $this->profil->sphinx->ent->host); + define('SPHINX_PORT', intval($this->profil->sphinx->ent->port)); + } + + protected function _defineMail() + { + //Messagerie + define('SMTP_HOST', $this->profil->mail->smtp_host); + define('SMTP_PORT', ''); + define('SMTP_USER', ''); + define('SMTP_PASS', ''); + } + +} \ No newline at end of file diff --git a/src/Scores/Conso/Export.php b/src/Scores/Conso/Export.php new file mode 100644 index 0000000..9845793 --- /dev/null +++ b/src/Scores/Conso/Export.php @@ -0,0 +1,95 @@ + "Identifiant", + 'referenceParDefaut' => "Service", + 'page' => "Code Requete", + 'pageLib' => "Libellé Requete", + 'params' => "Paramètres", + 'siren' => "Siren", + 'nic' => "Nic", + 'raisonSociale' => "Raison Sociale", + 'cp' => "CP", + 'ville' => "Ville", + 'dateHeure' => "DateHeure", + 'nbDoublon' => "Nb Doublon", + ); + + protected $pageLib = array(); + + protected $data = array(); + + /** + * Export des logs de conso sous forme de fichier CSV + */ + public function __construct() + { + $this->setPageLib(); + } + + public function setData($d) + { + $this->data = $d; + } + + /** + * Formattage des données pour le CSV + * @param string $filename + * @param string $addEntete + */ + public function export($filename, $addEntete = true) + { + $enteteCode = array_keys($this->entete); + $enteteLabel = array_values($this->entete); + + // Create CSV File + $csv = Writer::createFromPath($filename, 'w'); + // Insert the CSV header + $csv->insertOne($enteteLabel); + + // --- Parcours des données + foreach ($this->data as $data){ + $row = array(); + foreach ($enteteCode as $entete) { + if (array_key_exists($entete, $data)) { + $row[] = $data[$entete]; + } else if (property_exists($this, $entete)){ + $code = str_replace('Lib', '', $entete); + if (array_key_exists($data[$code], $this->{$entete})) { + $row[] = $this->{$entete}[$data[$code]]; + } else { + $row[] = 'NO LABEL'; + } + } else { + $row[] = 'UNKNOWN'; + } + } + + // Insert Data + $csv->insertOne($row); + } + } + + /** + * Récupération des libellés de requete + */ + protected function setPageLib() + { + $libM = new Application_Model_Sdv1LogsItem(); + $libSql = $libM->select()->from($libM, array('Code', 'Label')); + $libResult = $libM->fetchAll($libSql); + if (count($libResult) > 0) { + foreach ($libResult as $l) { + $this->pageLib[$l->Code] = $l->Label; + } + } + } + +} \ No newline at end of file diff --git a/src/Scores/Conso/File.php b/src/Scores/Conso/File.php new file mode 100644 index 0000000..ebdb616 --- /dev/null +++ b/src/Scores/Conso/File.php @@ -0,0 +1,135 @@ +table = $table; + $this->sql = $this->table->select(); + } + + /** + * Array of login + * @param array $login + */ + public function setLogin($login) + { + $this->login = $login; + } + + /** + * Date au format AAAAMM + * @param string $date + */ + public function setDate($date) + { + $this->date = $date; + } + + /** + * Code de l'élément à compter + * @param string $item + */ + public function setItem($item) + { + $this->item = $item; + } + + /** + * Retourne la requete + * @return Zend_Db_Select + */ + public function getSqlRule() + { + $this->addSqlLogin(); + $this->addSqlItem(); + $this->addSqlDate(); + + return $this->sql; + } + + /** + * + * @param unknown $name + * @param unknown $value + */ + public function setOption($name, $value) + { + if ( null === $this->item ) { + return new Zend_Exception('Item is not set !'); + } + + if ($name == 'duplicate') { + if ( !array_key_exists('duplicate', $this->rules[$this->item]) ) { + switch ( strtolower($value) ) { + case 'day': + case 'jour': + $this->rules[$this->item]['duplicate'] = 'day'; + break; + case 'month': + case 'mois': + case 'period': + case 'periode': + $this->rules[$this->item]['duplicate'] = 'period'; + break; + } + } + } + } + + /** + * + */ + public function addSqlLogin() + { + $this->sql->where("login IN ('".join("','", $this->login)."')"); + } + + public function addSqlDate() + { + $formatedDate = substr($this->date,0,4).'-'.substr($this->date,4,2); + $this->sql->where("dateAjout BETWEEN '".$formatedDate."-01 00:00:00' AND '".$formatedDate."-31 23:59:59'"); + } + + public function addSqlItem() + { + $this->sql->from($this->table, array('COUNT(*) AS NB')); + + $rule = $this->rules[$this->item]; + + //Apply item parameters + /*if ( array_key_exists('params', $rule) && count($rule['params'])>0 ) { + foreach ( $rule['params'] as $param ) { + $this->sql->where($param); + } + }*/ + $this->sql->where('source=?', $this->item); + + $this->sql->order('dateAjout ASC'); + } + +} \ No newline at end of file diff --git a/src/Scores/Conso/Flux.php b/src/Scores/Conso/Flux.php new file mode 100644 index 0000000..8f63773 --- /dev/null +++ b/src/Scores/Conso/Flux.php @@ -0,0 +1,66 @@ +table = $table; + $this->sql = $this->table->select(); + } + + /** + * Date au format AAAAMM + * @param string $date + * @param boolean $stock + */ + public function setDate($date, $stock = false) + { + $this->date = $date; + $this->dateStock = $stock; + } + + public function setCode($name) + { + $this->code = $name; + } + + public function setType($name) + { + + } + + public function getSqlRule() + { + $this->sql->from($this->table, array('COUNT(*) AS NB')); + + $formatedDate = substr($this->date,0,4).'-'.substr($this->date,4,2); + if ($this->dateStock === true) { + $this->sql->where("dateSuppr = 0"); + } else { + $this->sql->where("dateAjout BETWEEN '".$formatedDate."-01 00:00:00' AND '".$formatedDate."-31 23:59:59'"); + } + + $this->sql->where('idClient=?', $this->code); + + return $this->sql; + } + +} \ No newline at end of file diff --git a/src/Scores/Conso/Logs.php b/src/Scores/Conso/Logs.php new file mode 100644 index 0000000..f30223e --- /dev/null +++ b/src/Scores/Conso/Logs.php @@ -0,0 +1,358 @@ + array( + * 'params' => array of supplemental sql and where + * 'duplicate' => none, day, month, period (specified if this params must not change) + * ) + * @var array + */ + protected $rules = array ( + 'identite' => array(), + 'annonces' => array(), + 'dirigeants' => array(), + 'dirigeantsop' => array(), + 'evenements' => array(), + 'etablissements' => array(), + 'liens' => array( + 'duplicate' => 'none', + ), + 'competences' => array(), + 'kbis' => array(// à correler avec la table des commandes - Non fonctionnel + 'duplicate' => 'day', + ), + 'synthese' => array(), + 'ratios' => array(), + 'bilan' => array( + 'duplicate' => 'none', + ), + 'indiscore' => array(), + 'indiscore2' => array(), + 'indiscore3' => array(), + 'indiscorep' => array(), + 'indiscore2p' => array(), + 'indiscore3p' => array(), + 'flux' => array(), + 'liassexls' => array( + 'duplicate' => 'none', + ), + 'rapport1' => array(), + 'rapport2' => array(), + 'rapport3' => array(), + 'marques' => array(), + 'banque' => array(), + 'conventions' => array(), + 'groupeinfos' => array(), + 'groupesarbo' => array(), + 'infosreg' => array(), + 'rechcsv' => array( + 'duplicate' => 'none', + ), + 'greffe_bilans' => array( + 'params' => array( + "params != 'Liste'" + ), + 'group' => array('login', 'siren', 'page', 'params', 'raisonSociale', 'period'), + ), + 'greffe_actes' => array( + 'params' => array( + "params != 'Liste'" + ), + 'group' => array('login', 'siren', 'page', 'params', 'raisonSociale', 'period'), + ), + 'greffe_statuts' => array( + 'group' => array('login', 'siren', 'page', 'params', 'raisonSociale', 'period'), + ), + 'bourse' => array(), + 'scorecsf' => array(), + 'avis_situation' => array(), + 'privileges' => array(), + 'commandeAsso' => array(), + 'privcumul' => array(), + 'privdetail' => array(), + 'uploadbilan' => array(), + 'histobodacc' => array(), + 'aviscredit' => array(), + 'tva' => array(), + 'sirenExiste' => array(), + 'histobodacc' => array(), + 'valo' => array(), + 'rnvp' => array(), + 'avisrncs' => array(), + 'affairelist' => array(), + 'affairedetail' => array(), + ); + + /** + * @var Zend_Db_Table_Abstract + */ + protected $table; + + /** + * + * @var Zend_Db_Select + */ + protected $sql; + + /** + * + * @param Zend_Db_Table_Abstract $table + */ + public function __construct(Zend_Db_Table_Abstract $table) + { + $this->table = $table; + $this->sql = $this->table->select(); + } + + /** + * Array of login + * @param array $login + */ + public function setLogin($login) + { + $this->login = $login; + } + + /** + * Date au format AAAAMM + * @param string $date + */ + public function setDate($date) + { + $this->date = $date; + } + + /** + * Code de l'élément à compter + * @param string $item + */ + public function setItem($item) + { + $this->item = $item; + } + + /** + * Retourne requete SQL avec les règles + * @return Zend_Db_Select + */ + public function getSqlRule($file = false) + { + $this->addSqlLogin(); + $this->addSqlItem($file); + $this->addSqlDate(); + + return $this->sql; + } + + /** + * Retourne requete SQL + * @return Zend_Db_Select + */ + public function getSql() + { + $this->addSqlLogin(); + $this->addSqlDate(); + + $columns = array( + 'LOWER(login) AS login', 'page', 'LPAD(siren, 9, 0) AS siren', 'LPAD(nic, 5, 0) AS nic', + 'params', 'raisonSociale', 'cp', 'ville', 'dateHeure', new Zend_Db_Expr('"none" as nbDoublon')); + $this->sql->from($this->table, $columns); + + return $this->sql; + } + + /** + * + * @param unknown $name + * @param unknown $value + */ + public function setOption($name, $value) + { + if ( null === $this->item ) { + return new Zend_Exception('Item is not set !'); + } + + if ($name == 'duplicate') { + if ( !array_key_exists('duplicate', $this->rules[$this->item]) ) { + switch ( strtolower($value) ) { + case 'day': + case 'jour': + $this->rules[$this->item]['duplicate'] = 'day'; + break; + case 'month': + case 'mois': + case 'period': + case 'periode': + $this->rules[$this->item]['duplicate'] = 'period'; + break; + } + } + } + } + + /** + * + */ + public function addSqlLogin() + { + $this->sql->where($this->table->info('name').".login IN ('".join("','", $this->login)."')"); + } + + public function addSqlDate() + { + $formatedDate = substr($this->date,0,4).'-'.substr($this->date,4,2); + $this->sql->where("dateHeure BETWEEN '".$formatedDate."-01 00:00:00' AND '".$formatedDate."-31 23:59:59'"); + } + + public function addSqlItem($file = false) + { + $rule = array(); + + if ( array_key_exists($this->item, $this->rules) ){ + $rule = $this->rules[$this->item]; + } + + // --- Group to deduplicate + if ( array_key_exists('duplicate', $rule) ) { + switch($rule['duplicate']) { + + case 'day': + if ($file === false ) { + $columns = array('COUNT(*) AS doublon', "DATE_FORMAT(dateHeure, '%Y%m%d') AS period"); + } else { + $columns = array( + 'LOWER('.$this->table->info('name').'.login) AS login', + 'page', + 'LPAD(siren, 9, 0) AS siren', + 'LPAD(nic, 5, 0) AS nic', + 'params', + 'raisonSociale', + 'cp', + 'ville', + 'dateHeure', + "DATE_FORMAT(dateHeure, '%Y%m%d') AS period", + 'COUNT(*) AS nbDoublon' + ); + } + $this->sql->from($this->table, $columns); + + if ( array_key_exists('group', $rule) ) { + $this->sql->group($rule['group']); + } else { + $this->sql->group(array('login', 'siren', 'page', 'raisonSociale', 'period')); + } + break; + + case 'period': + if ($file === false ) { + /*SELECT count(doublon) as NB FROM () test*/ + $columns = array('COUNT(*) AS doublon', "DATE_FORMAT(dateHeure, '%Y%m') AS period"); + } else { + $columns = array( + 'LOWER('.$this->table->info('name').'.login) AS login', + 'page', + 'LPAD(siren, 9, 0) AS siren', + 'LPAD(nic, 5, 0) AS nic', + 'params', + 'raisonSociale', + 'cp', + 'ville', + 'dateHeure', + "DATE_FORMAT(dateHeure, '%Y%m') AS period", + 'COUNT(*) AS nbDoublon' + ); + } + $this->sql->from($this->table, $columns); + + if ( array_key_exists('group', $rule) ) { + $this->sql->group($rule['group']); + } else { + $this->sql->group(array('login', 'siren', 'page', 'raisonSociale', 'period')); + } + + break; + + case 'none': + default: + if ($file === false ) { + $columns = array('dateHeure AS period'); + } else { + $columns = array( + 'LOWER('.$this->table->info('name').'.login) AS login', + 'page', + 'LPAD(siren, 9, 0) AS siren', + 'LPAD(nic, 5, 0) AS nic', + 'params', + 'raisonSociale', + 'cp', + 'ville', + 'dateHeure', + new Zend_Db_Expr('"none" as nbDoublon') + ); + } + $this->sql->from($this->table, $columns); + break; + } + } + + // --- No duplicate rules + if ( !array_key_exists('duplicate', $rule) || count($rule) == 0 ) { + if ($file === false ) { + $columns = array('dateHeure'); + } else { + $columns = array( + 'LOWER('.$this->table->info('name').'.login) AS login', + 'page', + 'LPAD(siren, 9, 0) AS siren', + 'LPAD(nic, 5, 0) AS nic', + 'params', + 'raisonSociale', + 'cp', + 'ville', + 'dateHeure', + new Zend_Db_Expr('"none" as nbDoublon') + ); + } + $this->sql->from($this->table, $columns); + } + + // --- Apply item parameters + if ( array_key_exists('params', $rule) && count($rule['params'])>0 ) { + foreach ( $rule['params'] as $param ) { + $this->sql->where($param); + } + } + + if ($file === true) { + $this->sql->setIntegrityCheck(false) + ->joinLeft('utilisateurs', 'utilisateurs.login='.$this->table->info('name').'.login', array('referenceParDefaut'), 'sdv1'); + } + + $this->sql->where('page=?', $this->item); + + $this->sql->order('dateHeure ASC'); + } + +} \ No newline at end of file diff --git a/src/Scores/Conso/Surveillances.php b/src/Scores/Conso/Surveillances.php new file mode 100644 index 0000000..113afcd --- /dev/null +++ b/src/Scores/Conso/Surveillances.php @@ -0,0 +1,165 @@ + array( + * 'params' => array of supplemental sql and where + * 'duplicate' => none, day, month, period (specified if this params must not change) + * ) + * @var array + */ + protected $rules = array ( + 'annonces' => array(), + 'insee' => array(), + 'bilans' => array(), + 'score' => array(), + 'actes' => array(), + 'dirigeants' => array(), + 'paiements' => array(), + 'liens' => array(), + 'privileges' => array(), + ); + + /** + * @var Zend_Db_Table_Abstract + */ + protected $table; + + /** + * + * @var Zend_Db_Select + */ + protected $sql; + + /** + * + * @param Zend_Db_Table_Abstract $table + */ + public function __construct(Zend_Db_Table_Abstract $table) + { + $this->table = $table; + $this->sql = $this->table->select(); + } + + /** + * Array of login + * @param array $login + */ + public function setLogin($login) + { + $this->login = $login; + } + + /** + * Date au format AAAAMM + * @param string $date + * @param boolean $stock + */ + public function setDate($date, $stock = false) + { + $this->date = $date; + $this->dateStock = $stock; + } + + /** + * Code de l'élément à compter + * @param string $item + */ + public function setItem($item) + { + $this->item = $item; + } + + /** + * Retourne la requete + * @return Zend_Db_Select + */ + public function getSqlRule() + { + $this->addSqlLogin(); + $this->addSqlItem(); + $this->addSqlDate(); + + return $this->sql; + } + + /** + * + * @param unknown $name + * @param unknown $value + */ + public function setOption($name, $value) + { + if ( null === $this->item ) { + return new Zend_Exception('Item is not set !'); + } + + if ($name == 'duplicate') { + if ( !array_key_exists('duplicate', $this->rules[$this->item]) ) { + switch ( strtolower($value) ) { + case 'day': + case 'jour': + $this->rules[$this->item]['duplicate'] = 'day'; + break; + case 'month': + case 'mois': + case 'period': + case 'periode': + $this->rules[$this->item]['duplicate'] = 'period'; + break; + } + } + } + } + + /** + * + */ + public function addSqlLogin() + { + $this->sql->where("login IN ('".join("','", $this->login)."')"); + } + + public function addSqlDate() + { + $formatedDate = substr($this->date,0,4).'-'.substr($this->date,4,2); + if ($this->dateStock === true) { + $this->sql->where("dateSuppr = 0"); + } else { + $this->sql->where("dateAjout BETWEEN '".$formatedDate."-01 00:00:00' AND '".$formatedDate."-31 23:59:59'"); + } + + } + + public function addSqlItem() + { + $this->sql->from($this->table, array('COUNT(*) AS NB')); + + $rule = $this->rules[$this->item]; + + //Apply item parameters + /*if ( array_key_exists('params', $rule) && count($rule['params'])>0 ) { + foreach ( $rule['params'] as $param ) { + $this->sql->where($param); + } + }*/ + $this->sql->where('source=?', $this->item); + + $this->sql->order('dateAjout ASC'); + } + +} \ No newline at end of file diff --git a/src/Scores/Courrier/Generate.php b/src/Scores/Courrier/Generate.php new file mode 100644 index 0000000..58b41bb --- /dev/null +++ b/src/Scores/Courrier/Generate.php @@ -0,0 +1,373 @@ +path = realpath($c->profil->path->shared).'/courrier/'; + + $this->info = new stdClass(); + $this->info->ref = $numCommande; + $this->info->refType = $type; + } + + public function setInfosCommande() + { + $typeCommande = $this->info->refType; + $id = $this->info->ref; + + if ($typeCommande == 'ac') { + + $commande = new Application_Model_Sdv1GreffeCommandesAc(); + $sql = $commande->select()->where('id = ?', $id); + $result = $commande->fetchRow($sql); + $typeDocument = 'actes'; + + $gM = new Application_Model_JoGreffesActes(); + $sql = $gM->select() + ->where('siren=?', $result->siren) + ->where('num_depot=?', $result->depotNum) + ->where('date_depot=?', $result->depotDate) + ->where('num_acte=?', $result->acteNum) + ->where('date_acte=?', $result->acteDate) + ->where('type_acte=?', $result->acteType); + $document = $gM->fetchRow($sql); + + $this->info->libDocument = $document->type_acte_libelle; + $this->info->dateDocument = $result->acteDate; + $this->info->dateDepot = $result->acteType; + + } else if ($typeCommande == 'bi') { + + $commande = new Application_Model_Sdv1GreffeCommandesBi(); + $sql = $commande->select()->where('id = ?', $id); + $result = $commande->fetchRow($sql); + $typeDocument = 'bilans'; + + $gM = new Application_Model_JoGreffesBilans(); + $sql = $gM->select() + ->where('siren=?', $result->siren) + ->where('date_cloture=?', $result->bilanCloture); + if ( $result->bilanType == 'sociaux' || $result->bilanType == '' ) { + $sql->where("(type_comptes='sociaux' OR type_comptes='')"); + } else { + $sql->where('type_comptes=?', $result->bilanType); + } + $sql->order('dateInsert DESC')->order('num_depot DESC')->limit(1); + $document = $gM->fetchRow($sql); + + + $this->info->libDocument = ''; + $this->info->dateDocument = $result->bilanCloture; + + } else if ($typeCommande == 'kb') { + + $commande = new Application_Model_Sdv1GreffeCommandesKb(); + $sql = $commande->select()->where('id = ?', $id); + $result = $commande->fetchRow($sql); + $typeDocument = 'kbis'; + if ($result->type == 'M') { + $this->info->type = 'MAIL'; + } + + } + //Assignation des variables + $this->info->siren = $result->siren; + $this->info->typeDocument = $typeDocument; + + } + + public function setInfosIdentite() + { + // @todo : How to include old framework + $insee = new Metier_Insee_MInsee(); + $reponse = $insee->getIdentiteEntreprise($this->info->siren); + + $this->info->commune = $reponse['codeCommune']; + $this->info->dept = $reponse['Dept']; + $this->info->siret = $reponse['Siret']; + $this->info->numRC = $reponse['NumRC']; + //$info->siren = substr($siren, 0, 3).' '.substr($siren, 3, 3).' '.substr($siren, 6, 3); + $this->info->nom = htmlspecialchars_decode($reponse['Nom'], ENT_QUOTES); + $this->info->adresse = htmlspecialchars_decode($reponse['Adresse'], ENT_QUOTES).' '; + if (empty($reponse['Adresse2']) == false) { + $info->adresse .= $reponse['Adresse2'].' '; + } + $this->info->adresse .= "\n".$reponse['CP'].' '.$reponse['Ville']; + } + + public function setInfosTribunal() + { + // Adresse du tribunal de commerce + // @todo : How to include old framework + $iBodacc = new Metier_Bodacc_MBodacc(); + $reponse = $iBodacc->getTribunauxParCommune($this->info->dept.$this->info->commune); + + $tribunalLib = $reponse[0]['triNom']; + if (preg_match('/(A|B|C|D)/i', $this->info->numRC)) { + $libTrib = ' RCS '. + preg_replace('/(^TC |^TI |^TGIcc |^TMX )/i', '', $tribunalLib); + } else if (preg_match('/(P)/i', $this->info->numRC)) { + $libTrib = ' RSAC '. + preg_replace('/(^TC |^TI |^TGIcc |^TMX )/i', '', $tribunalLib); + } + $this->info->tribunalCode = $reponse[0]['triCode']; + $this->info->libTrib = $libTrib; + + + $this->info->tribunal->Adr = strtoupper(preg_replace('/ +/',' ', + $reponse[0]['triAdrNum'].' '. + $reponse[0]['triAdrIndRep'].' '. + $reponse[0]['triAdrTypeVoie'].' '. + $reponse[0]['triAdrVoie'])); + $this->info->tribunal->AdrComp = strtoupper($reponse[0]['triAdrComp']); + $this->info->tribunal->CP = $reponse[0]['triCP']; + $this->info->tribunal->Ville = strtoupper($reponse[0]['triVille']); + } + + public function setTarifs() + { + $tarifs = new Application_Model_Sdv1GreffeTarifs(); + + $sql = $tarifs->select()->where('codeTribunal = ?', $this->info->tribunalCode) + ->where('type = ?', $this->info->typeDocument) + ->where('annee = ?', date('Y')); + $result = $tarifs->fetchAll($sql)->toArray(); + + if (count($result) == 0) { + echo 'Commande '.$this->info->ref.' - Pas de tarifs défini pour le tribunal '. + $this->info->tribunal->Nom.' ('.$this->info->tribunalCode.')'; + exit; + } + $this->info->prix = number_format($result[0]['prix'], 2, ',', ' '); + $this->info->enveloppe = $result[0]['enveloppe']; + } + + protected function setDestinataire() + { + // Destinataire + $this->info->destinataire = "REGISTRE DU COMMERCE - GREFFE\n". + $this->normaliseVoie(trim($this->info->tribunal->Adr))."\n". + $this->normaliseVoie($this->info->tribunal->AdrComp)."\n". + $this->info->tribunal->CP.' '.$this->info->tribunal->Ville."\n"; + } + + protected function setSujet() + { + // Type de document demandé (actes ou bilans pour l'instant) + // [un Kbis / l'état d'endettement / la copie de jugement de XXX en date du XXX] + if ($this->info->typeDocument == 'bilans') { + + $this->info->sujet = 'une copie du bilan au '. + substr($this->info->dateDocument, 6, 2).'/'. + substr($this->info->dateDocument, 4, 2).'/'. + substr($this->info->dateDocument, 0, 4); + + } else if ($this->info->typeDocument == 'actes') { + + $this->info->sujet = 'une copie de l\'acte '.$this->info->libDocument; + + $this->info->sujet .= ' en date du '. + substr($this->info->dateDocument, 6, 2).'/'. + substr($this->info->dateDocument, 4, 2).'/'. + substr($this->info->dateDocument, 0, 4); + + } else if ($this->info->typeDocument == 'kbis') { + + $this->info->sujet = 'un extrait RCS'; + + } + } + + protected function setSociete() + { + // Societe + $this->info->societe = $this->info->nom."\n".'( '.$this->info->siren.$this->info->libTrib.' )'."\n"; + $this->info->societe .= $this->normaliseVoie($this->info->adresse); + } + + protected function setMontant() + { + // Piece jointe et montant + if ($this->info->enveloppe) { + $this->info->montant = 'Ci-joint une enveloppe timbrée ainsi qu\'un '. + 'chèque d\'un montant de '.$this->info->prix. + ' euros en règlement de cette commande.'; + } else { + $this->info->montant = 'Ci-joint un chèque d\'un montant de '.$this->info->prix. + ' euros en règlement de cette commande.'; + } + } + + public function computeOdt() + { + $config = array( + 'ZIP_PROXY' => 'PhpZipProxy', + ); + + $odf = new Odf(__DIR__.'/Model/modeleLettreGreffe.odt', $config); + + $this->setInfosCommande(); + $this->setInfosIdentite(); + $this->setInfosTribunal(); + $this->setTarifs(); + $this->setDestinataire(); + $this->setSujet(); + $this->setSociete(); + $this->setMontant(); + + $file = $this->info->siren.'-'.$this->info->ref.'.odt'; + + $odf->setVars('destinataire', $this->info->destinataire, true, 'UTF-8'); + $odf->setVars('date', date('d/m/Y'), true, 'UTF-8'); + $odf->setVars('ref', $this->info->ref, true, 'UTF-8'); + $odf->setVars('sujet', $this->info->sujet, true, 'UTF-8'); + $odf->setVars('societe', $this->info->societe, true, 'UTF-8'); + $odf->setVars('montant', $this->info->montant, true, 'UTF-8'); + if ($this->info->type == 'MAIL') { + $odf->setVars('bymail',"ou à votre convenance par mail à : support@scores-decisions.com", true, 'UTF-8'); + } + $odf->saveToDisk($this->path.$file); + + if (file_exists($this->path.$file) == true) { + header('Content-Transfer-Encoding: none'); + header('Content-type: application/vnd.oasis.opendocument.text'); + header('Content-Length: '.filesize($this->path.$file)); + header('Content-MD5: '.base64_encode(md5_file($this->path.$file))); + header('Content-Disposition:attachment; filename="'.$file.'"'); + header('Cache-Control: private, max-age=0, must-revalidate'); + header('Pragma: public'); + ini_set('zlib.output_compression','0'); + echo file_get_contents($this->path.$file); + } else { + echo 'Erreur Génération du fichier'; + } + } + + public function computePdf() + { + $this->setInfosCommande(); + $this->setInfosIdentite(); + $this->setInfosTribunal(); + $this->setTarifs(); + $this->setDestinataire(); + $this->setSujet(); + $this->setSociete(); + $this->setMontant(); + + // initiate PDF + $pdf = new Scores_Courrier_Pdf(); + /* + * Définition des marges + * Left, Top et Right + * Dimension du logo d'entete : + **/ + $pdf->SetMargins(25, 50, 25); + $border = 0; + // add a page + $pdf->AddPage(); + $pdf->SetFont("times", "", 10); + + //Position de départ + $pdf->SetY(50); + + //Bloc Addresse destinataire + $largeur = 80; + $positionX = 105; + $pdf->MultiCell($largeur, 5, $this->info->destinataire, $border, 'L', 0, 1, $positionX); + + //Bloc Lieu, date + $date = date('d/m/Y'); + $txt = "Rambouillet, le $date"; + $positionY = $pdf->GetY()+5; + $pdf->MultiCell($largeur, 5, $txt, $border, 'L', 0, 1, $positionX, $positionY); + + //Bloc objet + $positionY = $pdf->GetY()+5; + $pdf->MultiCell(20, 5, "Objet:", $border, 'L', 0, 0, '', $positionY, true); + $pdf->MultiCell(0, 5, "Commande de document", $border, 'L', 0, 1, '', '', true); + //Bloc ref + $pdf->MultiCell(20, 5, "Réf.", $border, 'L', 0, 0, '', '', true); + $pdf->MultiCell(0, 5, $this->info->ref, $border, 'L', 0, 1, '', '', true);; + //Bloc titre + $positionY = $pdf->GetY()+5; + $pdf->MultiCell(0, 5, "Madame, Monsieur,", $border, 'L', 0, 1, '', $positionY, true); + + //Type de document demandé (actes ou bilans pour l'instant) + //[un Kbis / l'état d'endettement / la copie de jugement de XXX en date du XXX ] + $positionY = $pdf->GetY()+2; + $pdf->MultiCell(0, 5, "Nous vous prions de nous faire parvenir $this->info->sujet concernant la société:", $border, 'L', 0, 1, '', $positionY, true); + + //Bloc société + $positionY = $pdf->GetY()+2; + $pdf->MultiCell(0, 5, $this->info->societe, $border, 'L', 0, 1, '', $positionY, true); + + //Bloc pièce jointe + $positionY = $pdf->GetY()+5; + $pdf->MultiCell(0, 5, $this->info->montant, $border, 'L', 0, 1, '', $positionY, true); + + //Bloc intitulé adresse reception + $positionY = $pdf->GetY()+2; + $pdf->MultiCell(0, 5, + "Veuillez nous renvoyer le(s) document(s) par retour à l'adresse suivante:", + $border, 'L', 0, 1, '', $positionY, true); + + //Bloc adresse s&d + $positionY = ''; + $pdf->MultiCell(0, 5, + "SCORES ET DECISIONS" . "\n" . + "19 rue Clairefontaine". "\n" . + "78120 RAMBOUILLET" . "\n" + , $border, 'L', 0, 1, '', $positionY, true); + + if ($this->info->type == 'MAIL') { + $positionY = $pdf->GetY()+2; + $pdf->MultiCell(0, 5, + "ou à votre convenance par mail à : support@scores-decisions.com", + $border, 'L', 0, 1, '', $positionY, true); + } + + //Bloc formule politesse + $positionY = $pdf->GetY()+2; + $pdf->MultiCell(0, 5, "Dans l'attente de notre prochain échange, nous vous prions de recevoir, Madame, Monsieur, l'expression de nos plus sincères salutations.", $border, 'L', 0, 1, '', $positionY, true); + + $file = $this->info->siren.'-'.$this->info->ref.'.pdf'; + $pdf->Output($this->path.$file, 'F'); + if(file_exists($path.$file)) + { + $content_type = 'application/pdf'; + header('Content-Transfer-Encoding: none'); + header('Content-type: '.$content_type.''); + header('Content-Length: '.filesize($this->path.$file)); + header('Content-MD5: '.base64_encode(md5_file($this->path.$file))); + header('Content-Disposition: attachment, filename="'.$file.'"'); + header('Cache-Control: private, max-age=0, must-revalidate'); + header('Pragma: public'); + ini_set('zlib.output_compression','0'); + echo file_get_contents($this->path.$file); + } + } + + protected function normaliseVoie($txt) + { + $replace_pairs = array( + 'BD ' => 'BOULEVARD ', + 'BVD ' => 'BOULEVARD ', + 'AV ' => 'AVENUE ', + 'AVE ' => 'AVENUE ', + 'PL ' => 'PLACE ', + 'PLA ' => 'PLACE ', + 'PLAC ' => 'PLACE ', + 'ESP ' => 'ESP ', + 'RTE ' => 'ROUTE ', + 'ST ' => 'SAINT ', + 'STE ' => 'SAINTE ', + 'QU ' => 'QUAI ' + ); + return strtr($txt, $replace_pairs); + } +} \ No newline at end of file diff --git a/src/Scores/Courrier/Model/modele.odt b/src/Scores/Courrier/Model/modele.odt new file mode 100644 index 0000000000000000000000000000000000000000..f3f65a953351aa41feaf7dff8fb1e0e75ec29fea GIT binary patch literal 75650 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 U{@r0Xu)n9UQB#ZpHhcp93#^EE82|tP literal 0 HcmV?d00001 diff --git a/src/Scores/Courrier/Model/modele.pdf b/src/Scores/Courrier/Model/modele.pdf new file mode 100644 index 0000000000000000000000000000000000000000..f2a5c48e46e6f481b8f6a1d21b97a5fa8dcb8ef7 GIT binary patch literal 69588 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

    `y6g>IZ_<0+=Po1lzy7@BBmI9=E?RS>nX7J6eF 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

    (QQ$W9BYW({SyVWj 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 literal 0 HcmV?d00001 diff --git a/src/Scores/Courrier/Pdf.php b/src/Scores/Courrier/Pdf.php new file mode 100644 index 0000000..c118c90 --- /dev/null +++ b/src/Scores/Courrier/Pdf.php @@ -0,0 +1,22 @@ +_tplIdx)) { + $file = __DIR__.'/Model/modele.pdf'; + $this->setSourceFile($file); + $this->_tplIdx = $this->importPage(1); + } + $this->useTemplate($this->_tplIdx); + } + + function Footer() { + } +} \ No newline at end of file diff --git a/src/Scores/Extract/Dict.php b/src/Scores/Extract/Dict.php new file mode 100644 index 0000000..3a5cd64 --- /dev/null +++ b/src/Scores/Extract/Dict.php @@ -0,0 +1,680 @@ + array( + 'lib' => "SD : Identifiant - Etablissement", + 'help' => "Identifiant interne propre à SD, usage restreint", + 'columns' => array( + 'id' => 'Identifiant Interne', + ) + ), + 'source' => array( + 'lib' => "SD : Source" + //@todo : Yoann + ), + 'triCode' => array( + 'lib' => "?? : Code BODACC du Tribunal - Etablissement", + 'help' => "Code BODACC du tribunal, voir la table jo.tribunaux (à confirmer, sortir triNom) +
    Entreprise exclusivement INSEE pas de code tribunal", + 'columns' => array( + 'triCode' => '' + ) + ), + 'autre_id' => array( + 'lib' => "Autre ID (SIREN ou WALDEC)", + 'help' => "Doublon SIREN (source RNCS) ou WALDEC (source JOAFE) si association", + 'columns' => array( + 'autre_id' => "Autre ID (SIREN ou WALDEC)", + ), + ), + 'actif' => array( + 'lib' => 'SD : ACTIF', + //@todo : Yoann + ), + 'siege' => array( + 'lib' => "SD : Siège ou Etablissement", + 'help' => "Valeur : 0 les établissements Secondaires (source INSEE), + 1 l'établissement Siège de l'entreprise (source INSEE) ; + 2 notion RNCS désignant l'établissement Principal qui n'est pas obligatoirement le siège + http://www.greffe-tc-caen.fr/rcs_etabs.php", + ), + 'raisonSociale' => array( + 'lib' => "SD : Raison Sociale", + 'help' => "Regle de composition de la donnée" + ), + 'enseigne' => array( + 'lib' => "SD : Enseigne", + 'help' => "Regle de composition de la donnée" + ), + 'sigle' => array( + 'lib' => "SD : Sigle", + 'help' => "Regle de composition de la donnée" + ), + 'marques' => array( + 'lib' => "SD : Marques déposées", + 'help' => "Chaine de caractère assemblé - Regle de composition de la donnée" + ), + 'adr_num' => array( + 'lib' => "SD : Adresse Numéro dans la voie - Etablissement", + 'help' => "Regle de composition de la donnée" + ), + 'adr_btq' => array( + 'lib' => "SD : Adresse Bis/Ter/etc.. - Etablissement", + 'help' => "Regle de composition de la donnée" + ), + 'adr_typeVoie' => array( + 'lib' => "SD : Adresse Type de voie - Etablissement", + 'help' => "Regle de composition de la donnée" + ), + 'adr_libVoie' => array( + 'lib' => "SD : Adresse Libellé de la voie - Etablissement", + 'help' => "Regle de composition de la donnée" + ), + 'adr_comp' => array( + 'lib' => "SD : Adresse Complément - Etablissement", + 'help' => "Regle de composition de la donnée" + ), + 'adr_cp' => array( + 'lib' => "SD : Adresse Code Postal - Etablissement", + 'help' => "Regle de composition de la donnée" + ), + 'adr_ville' => array( + 'lib' => "SD : Adresse Ville - Etablissement", + 'help' => "Regle de composition de la donnée" + ), + 'adr_dep' => array( + 'lib' => "SD : Adresse Département - Etablissement", + 'help' => "Regle de composition de la donnée" + ), + 'adr_codeCom' => array( + 'lib' => "SD : Adresse Code Commune étab - Etablissement", + 'help' => "Regle de composition de la donnée" + ), + 'telEtab' => array( + 'lib' => "Téléphone" + ), + 'faxEtab' => array( + 'lib' => "Télécopie" + ), + 'cj' => array( + 'lib' => "Forme juridique" + ), + 'capital' => array( + 'lib' => "Capital" + ), + 'capitalDev' => array( + 'lib' => "Devise du capital" + ), + 'ape_etab' => array( + 'lib' => "SD : NAF Etablissement", + 'help' => "Code NAF 5 positions", + 'columns' => array( + 'ape_etab' => "SD : NAF Etablissement", + ), + ), + 'ape_entrep' => array( + 'lib' => "SD : NAF Entreprise", + 'help' => "Code NAF 5 positions", + 'columns' => array( + 'ape_entrep' => "SD : NAF Entreprise", + ), + ), + 'NaceEtab' => array( + 'lib' => "SD : NACE Etablissement", + 'help' => "", + 'columns' => array( + 'NaceEtab' => "SD : NACE Etablissement", + 'NaceEtabLib' => "SD : NACE Etablissement", + ), + ), + 'NaceEn' => array( + 'lib' => "SD : NACE Entreprise", + 'help' => "", + 'columns' => array( + 'NaceEn' => "SD : NACE Entreprise", + 'NaceEnLib' => "SD : NACE Entreprise", + ), + ), + 'SiretEnBase' => array( + 'lib' => "Vérifier la présence en base du siren/siret" + ), + 'etActifInsee' => array( + 'lib' => "Insee : Actif" + ), + 'nomInsee' => array( + 'lib' => 'Insee : Raison Sociale' + ), + 'nomInsee2' => array( + 'lib' => 'Insee : Raison Sociale (suite)' + ), + 'sigleInsee' => array( + 'lib' => 'Insee : Sigle' + ), + 'enseigneInsee' => array( + 'lib' => 'Insee : Enseigne' + ), + 'adrNumVoieInsee' => array( + 'lib' => 'Insee : Adresse - Numéro dans la voie' + ), + 'adrBtqInsee' => array( + 'lib' => 'Insee : Adresse - Bis/Ter/etc' + ), + 'adrTypeVoieInsee' => array( + 'lib' => 'Insee : Adresse - Type de voie' + ), + 'adrVoieInsee' => array( + 'lib' => 'Insee : Adresse - Libellé de la voie' + ), + 'adrCompInsee' => array( + 'lib' => 'Insee : Adresse - Complément' + ), + 'adrCPInsee' => array( + 'lib' => 'Insee : Adresse - Code Postal' + ), + 'adrVilleInsee' => array( + 'lib' => 'Insee : Adresse - Commune' + ), + 'adrDistSPInsee' => array( + 'lib' => 'Insee : Adresse - Distribution spéciale' + ), + 'CjInsee' => array( + 'lib' => "Insee : Forme juridique de l'entreprise" + ), + 'nafEnInsee' => array( + 'lib' => "Insee : NAF de l'entreprise" + ), + 'nafEtInsee' => array( + 'lib' => "Insee : NAF de l'etablissement" + ), + 'APRM' => array( + 'lib' => "Insee : APRM" + ), + 'ACTIVNAT' => array( + 'lib' => "Insee : ACTIVNAT" + ), + 'ORIGINE' => array( + 'lib' => "Insee : Origine de création de l'établissement" + ), + 'MODET' => array( + 'lib' => "Insee : MODET" + ), + 'EXPLET' => array( + 'lib' => 'Insee : EXPLET' + ), + 'LIEUACT' => array( + 'lib' => "Insee : LIEUACT" + ), + 'ACTISURF' => array( + 'lib' => "Insee : ACTISURF" + ), + 'DEFET' => array( + 'lib' => "Insee : Année MAJ de l'effectif de l'établissement" + ), + 'MODEN' => array( + 'lib' => "Insee : MODEN" + ), + 'PRODPART' => array( + 'lib' => "Insee : PRODPART" + ), + 'EXPLEN' => array( + 'lib' => "Insee : EXPLEN" + ), + 'DEFEN' => array( + 'lib' => "Insee : Année MAJ de l'effectif de l'entreprise" + ), + 'MONOREG' => array( + 'lib' => "Insee : Mono-régionalité" + ), + 'REGIMP' => array( + 'lib' => "Insee : Principale région d'implantation" + ), + 'MONOACT' => array( + 'lib' => "Insee : Mono-activité" + ), + 'DCREN' => array( + 'lib' => "Insee : Date de création de l'entreprise" + ), + 'SIEGE' => array( + 'lib' => "Insee : Siege", + 'help' => "Qualité de siege ou non de l'établissement", + 'columns' => array( + 'SIEGE' => 'Insee : Siege', + ) + ), + 'AUXILT' => array( + 'lib' => "Insee : Auxiliarité" + ), + 'SAISONAT' => array( + 'lib' => "Insee : Saisonalité" + ), + 'CIVILITE' => array( + 'lib' => "Insee : Civilité" + ), + 'TCA' => array( + 'lib' => "Insee : Tranche de chiffre d'affaire" + ), + 'TCAEXP' => array( + 'lib' => "Insee : Tranche de chiffre d'affaire à l'export" + ), + 'EFF_ENT' => array( + 'lib' => "Insee : Effectif de l'entreprise" + ), + 'DCRET' => array( + 'lib' => "Insee : Date de création de l'établissement" + ), + 'TEFF_ENT' => array( + 'lib' => "Insee : Tranche effectif entreprise", + ), + 'ADR_DEP' => array( + 'lib' => "Insee : Adresse - Département", + 'help' => "Département de localisation de l'établissement (2 caractères)", + 'columns'=> array( + 'ADR_DEP' => 'Insee : Departement', + ), + ), + 'ADR_COM' => array( + 'lib' => "Insee : Commune de localisation de l'établissement", + 'help' => "(3 chiffres)", + 'columns' => array( + 'ADR_COM' => "Insee : Code commune", + ), + ), + 'EFF_ET' => array( + 'lib' => "Insee : Effectif de l'établissement" + ), + 'TEFF_ET' => array( + 'lib' => "Insee : Tranche effectif etablissement", + ), + 'CODEVOIE' => array( + 'lib' => "Insee : Code voie", + 'help' => "Code Rivoli / Ex Fantoir", + ), + 'dateMajInsee' => array( + 'lib' => "Insee : Date de la dernière mise à jour" + ), + 'insRPET' => array( + 'lib' => "Insee : RPET" + ), + 'insDEPCOMEN' => array( + 'lib' => "Insee : Code commune siège" + ), + 'insRPEN' => array( + 'lib' => "Insee : RPEN" + ), + 'insARRONET' => array( + 'lib' => "Insee : Arrondissement de l'établissement" + ), + 'insCTONET' => array( + 'lib' => "Insee : Canton de l'établissement" + ), + 'insTCD' => array( + 'lib' => "Insee : Tranche de commune détaillé" + ), + 'insZEMET' => array( + 'lib' => "Insee : ZEMET" + ), + 'insDU' => array( + 'lib' => "Insee : DU" + ), + 'insTU' => array( + 'lib' => "Insee : TU" + ), + 'insUU' => array( + 'lib' => "Insee : UU" + ), + 'insMMINTRET' => array( + 'lib' => "Insee : MMINTRET", + ), + 'insMMINTREN' => array( + 'lib' => "Insee : MMINTREN", + ), + 'insRECME' => array( + 'lib' => "Insee : RCEM" + ), + 'insEAEANT' => array( + 'lib' => "Insee : EAEANT" + ), + 'insEAEAPET' => array( + 'lib' => "Insee : EAEAPET" + ), + 'insEAESEC1T' => array( + 'lib' => "Insee : EAESEC1T" + ), + 'insEAESEC2T' => array( + 'lib' => "Insee : EAESEC2T" + ), + 'insEAEANN' => array( + 'lib' => "Insee : EAEANN" + ), + 'insEAEAPEN' => array( + 'lib' => "Insee : EAEAPEN" + ), + 'insEAESEC1N' => array( + 'lib' => "Insee : EAESEC1N" + ), + 'insEAESEC2N' => array( + 'lib' => "Insee : EAESEC2N" + ), + 'insEAESEC3N' => array( + 'lib' => "Insee : EAESEC3N" + ), + 'insEAESEC4N' => array( + 'lib' => "Insee : EAESEC4N" + ), + 'dateMajNotice' => array( + 'lib' => "Insee : Date de la dernière MAJ notice" + ), + 'NBETEXPL' => array( + 'lib' => "Insee : Nombre d'établissement exploitant actif" + ), + 'entActiveRncs' => array( + 'lib' => "RNCS : Actif - Entreprise" + ), + 'numRC2' => array( + 'lib' => "RNCS : Numéro RC" + ), + 'raisonSocialeRncs' => array( + 'lib' => "RNCS : Raison Sociale" + ), + 'sigleRncs' => array( + 'lib' => "RNCS : Sigle" + ), + 'dateNaiss' => array( + 'lib' => "RNCS : Date Naissance PP" + ), + 'lieuNaiss' => array( + 'lib' => "RNCS : Lieu Naissance PP" + ), + 'nationalite' => array( + 'lib' => "RNCS : Nationalité PP" + ), + 'pays' => array( + 'lib' => "RNCS : Pays" + ), + 'nafEnRncs' => array( + 'lib' => "RNCS : NAF Entrepise" + ), + 'cjRncs' => array( + 'lib' => "RNCS : Forme juridique" + ), + 'dateImma' => array( + 'lib' => "RNCS : Date Immatriculation" + ), + 'dateRad' => array( + 'lib' => "RNCS : Date de radiation" + ), + 'capitalType' => array( + 'lib' => "RNCS : Type de capital" + ), + 'dateMajEnRncs' => array( + 'lib' => "RNCS : Date MAJ Entreprise" + ), + 'etActifRncs' => array( + 'lib' => "RNCS : Actif" + ), + 'siegeRncs' => array( + 'lib' => "RNCS : Siège" + ), + 'enseigneRncs' => array( + 'lib' => "RNCS : Enseigne" + ), + 'nomCommercialRncs' => array( + 'lib' => "RNCS : Nom Commercial" + ), + 'adrNumVoieRncs' => array( + 'lib' => "RNCS : Numéro" + ), + 'adrIndRepRncs' => array( + 'lib' => "RNCS : Adresse - Numéro" + ), + 'adrLibVoieRncs' => array( + 'lib' => "RNCS : Adresse - Bis/Ter/etc" + ), + 'adrTypeVoieRncs' => array( + 'lib' => "RNCS : Adresse - Type de la voie" + ), + 'adrVoieRncs' => array( + 'lib' => "RNCS : Adresse - Libellé de la voie" + ), + 'cpRncs' => array( + 'lib' => "RNCS : Adresse - Code postal" + ), + 'villeRncs' => array( + 'lib' => "RNCS : Adresse - Ville" + ), + 'adrCompRncs' => array( + 'lib' => "RNCS : Adresse - Complément" + ), + 'nafEtRncs' => array( + 'lib' => "RNCS : NAF Etablissement" + ), + 'dateMajEtRncs' => array( + 'lib' => "RNCS : Date MAJ établissement" + ), + 'isin' => array( + 'lib' => "Code ISIN (société en bourse)" + ), + 'tel' => array( + + ), + 'fax' => array(), + 'web' => array(), + 'mail' => array(), + 'nicSiege'=> array( + 'lib' => "NIC du siège (si nic absent)" + ), + 'tva'=> array( + 'lib' => "Numéro de TVA (non validés)" + ), + 'dateFermetureEn'=> array(), + 'dateFermetureEt'=> array(), + 'activite'=> array(), + 'situationJuridique'=> array(), + 'indiScore'=> array( + 'lib' => 'SD : indiScore', + ), + 'AdresseNormalise' => array( + 'lib' => 'AdresseNormalise', + 'columns' => array( + 'AdresseL1_NOM' => '', + 'AdresseL2_NOM2' => '', + 'AdresseL3_ADRCOMP' => '', + 'AdresseL4_VOIE' => '', + 'AdresseL5_DISTSP' => '', + 'AdresseL6_POST' => '', + 'AdresseL7_PAYS' => '', + ), + ), + 'AdresseNormaliseInsee' => array( + 'lib' => 'AdresseNormaliseInsee', + 'columns' => array( + 'L1_NOM' => 'L1_NOMEN', + 'L2_NOM2' => 'L2_COMP', + 'L3_ADRCOMP' => 'L3_CADR', + 'L4_VOIE' => 'L4_VOIE', + 'L5_DISTSP' => 'L5_DISP', + 'L6_POST' => 'L6_POST', + 'L7_PAYS' => 'L7_ETRG', + ), + ), + 'SiretSuc' => array( + 'lib' => 'INSEE : Siret Successeur', + 'help' => "", + 'columns' => array( + 'SiretSuc' => '', + 'SiretSucNbDem' => '', + 'SiretSucSiege' => '', + 'SiretSucActif' => '', + 'SiretSucCodeEve' => '', + 'SiretSucDateEve' => '', + 'SiretSucOrigine' => '', + ) + ), + 'dirigeant'=> array(), + 'bilanN'=> array('values'=>''), + 'bilanN1'=> array('values'=>''), + 'bilanN2'=> array('values'=>''), + 'annonces'=> array('values'=>''), + 'privilege' => array(), + 'GPS' => array( + 'lib' => 'SD : Coordonnées GPS - Etablissement', + 'help' => "", + 'columns' => array( + 'latitude' => "Latitude en degrés et décimales de degrés", + 'longitude' => "Longitude en degrés et décimales de degrés", + 'altitude' => "Altitude en mètres", + 'precis' => "Précision du géocodage (de 0=non géocodé à 8/9=géocodage à l'adresse)", + ) + ), + 'TelOrder' => array( + 'lib' => 'Telephone priorisé', + 'help' => "", + 'columns' => array() + ), + 'LienHead' => array( + 'lib' => 'Tête de lien financier', + 'help' => "", + 'columns' => array() + ), + 'LienHeadUltimate' => array( + 'lib' => 'Tête de lien ultime', + 'help' => "", + 'columns' => array() + ), + 'ZonePrioritaire' => array( + 'lib' => 'Zone Prioritaire', + 'help' => "", + 'columns' => array() + ), + 'AdresseDom'=> array( + 'lib' => 'AdresseDom', + 'help' => "", + 'columns' => array() + ), + 'Iris'=> array( + 'lib' => 'Iris', + 'help' => "", + 'columns' => array() + ), + ); + + public function __construct() + { + } + + //Vérifie que les entêtes du fichier sont correct + public function checkFileEntete($pathFile) + { + $posKeySiren = $posKeySiret = $posKeyNic = false; + $row = 0; + $error = array(); + if (($handle = fopen($pathFile, 'r')) !== false) { + while (($data = fgetcsv($handle, 0, ',', '"')) !== false) { + $num = count($data); + //Traitement de la première ligne + if ($row == 0) { + for ($c=0; $c < $num; $c++) { + //Détection clé importante + switch (strtolower($data[$c])) { + case 'siren': + $posKeySiren = $c; + break; + case 'nic': + $posKeyNic = $c; + break; + case 'siret': + $posKeySiret = $c; + break; + case 'ref': + //Clé réference + break; + default: + //Détection clé pour enrichissement + $values = false; + if (preg_match('/(.*)\((.*)\)/', $key, $matches)) { + $key = $matches[1]; + $values = $matches[2]; + } else { + $key = $data[$c]; + } + if (!array_key_exists($key, $this->tabDico)) { + $error[] = "Clé enrichissement $key incorrect"; + } + break; + } + } + if ($posKeySiren!==false && $posKeyNic!==false && $posKeySiret!==false || $posKeySiren!==false && $posKeySiret!==false) { + $error[] = "Trop de clé!"; + } + if ($posKeySiren===false && $posKeySiret===false) { + $error[] = "Aucune clé détecté!"; + } + } else { + //Erreur dans les entetes, on arrete + if (count($error)>0) { + break; + } + } + $row++; + } + fclose($handle); + if (count($error)>0) { + return $error; + } + return $row-1; + } + return false; + } + + //Retourne les clés de dictionnaire pour les données d'enrichissement + public function getDico() + { + return $this->tabDico; + } + + //Retourne le libellé pour chaque clés du dictionnaire + public function getDicoLib($key) + { + //Si () alors traitement champs spécial + if (preg_match('/(.*)\((.*)\)/', $key, $matches)) { + $key = $matches[1]; + } + + if (array_key_exists($key, $this->tabDico)) { + $element = $this->tabDico[$key]; + if (array_key_exists('lib', $element) && !empty($element['lib'])) { + return $element['lib']; + } + return $key; + } + return false; + } + + //Retourne le texte d'aide + public function getDicoHelp($key) + { + if (array_key_exists($key, $this->tabDico)) { + $element = $this->tabDico[$key]; + if (array_key_exists('help', $element) && !empty($element['help'])) { + return $element['help']; + } + return ''; + } + return false; + } + + //Retourne les colonnes de sortie + public function getDicoColumns($key) + { + if (array_key_exists($key, $this->tabDico)) { + $element = $this->tabDico[$key]; + if (array_key_exists('columns', $element)) { + return $element['columns']; + } + return array(); + } + return false; + } +} diff --git a/src/Scores/Locale/String.php b/src/Scores/Locale/String.php new file mode 100644 index 0000000..e0c61b3 --- /dev/null +++ b/src/Scores/Locale/String.php @@ -0,0 +1,88 @@ +enabled) { + $this->start = microtime(true); + $this->query = array('sql' => $sql, 'params' => $params, 'types' => $types, 'executionMS' => 0); + } + } + + /** + * {@inheritdoc} + */ + public function stopQuery() + { + if ($this->enabled) { + $time = microtime(true) - $this->start; + $this->total+= $time; + $this->query['executionTotal'] = $this->total; + $this->query['executionMS'] = $time; + if ($this->nb == 0) { + file_put_contents('logger.log', print_r($this->query, 1)); + } else { + file_put_contents('logger.log', print_r($this->query, 1), FILE_APPEND); + } + $this->nb++; + } + } +} diff --git a/src/Scores/Mail/Method.php b/src/Scores/Mail/Method.php new file mode 100644 index 0000000..a58a26d --- /dev/null +++ b/src/Scores/Mail/Method.php @@ -0,0 +1,129 @@ + smtp, sendmail, file + * Si method = smtp + * (host => IP, dns) + * + * Activer l'authentification + * (auth => login, plain, ....) + * (username => ) + * (password => ) + */ + public function __construct($config = null) + { + if ($config === null) { + $c = Zend_Registry::get('config'); + $this->config = $c->profil->mail; + } else { + $this->config = $config; + } + + $this->_charset = 'ISO-8859-15'; + + // --- Configuration du transport SMTP + if ($this->config->method == 'smtp') { + $config = array(); + + if (isset($this->config->auth)) { + $config['auth'] = $this->config->auth; + if (isset($this->config->username)) { + $config['username'] = $this->config->username; + } + if (isset($this->config->password)) { + $config['password'] = $this->config->password; + } + } + + if (isset($this->config->port)) { + $config['port'] = $this->config->port; + } + + $tr = new Zend_Mail_Transport_Smtp($this->config->host, $config); + } + + // --- Configuration transport Sendmail + if ($this->config->method == 'sendmail') { + $tr = new Zend_Mail_Transport_Sendmail(); + } + + // --- Configuration transport File + if ($this->config->method == 'file') { + $tr = new Zend_Mail_Transport_File(array('callback' => array($this, 'recipientFilename'))); + } + + $this->transport = $tr; + } + + /** + * Champ From en fonction de la clé de configuration + * @param string $configKey + */ + public function setFromKey($configKey) + { + $email = $this->config->email->$configKey; + $this->setFrom($email, ucfirst($configKey)); + } + + /** + * Champ To en fonction de la clé de configuration + * @param string $configKey + */ + public function addToKey($configKey) + { + $email = $this->config->email->$configKey; + $this->addTo($email, ucfirst($configKey)); + } + + /** + * Définit le sujet de l'email + * @param string $texte + */ + public function setSubjectC($texte = '') + { + $this->setSubject($this->txtConvert($texte)); + } + + /** + * Définit le corps de l'email au format texte + * @param string $texte + */ + public function setBodyTextC($texte = '') + { + $this->setBodyText($this->txtConvert($texte)); + } + + /** + * Définit le corps de l'email au format html + * @param string $html + */ + public function setBodyHtmlC($html = '') + { + $this->setBodyHtml($this->txtConvert($html)); + } + + /** + * Envoi de l'emai + */ + public function execute() + { + return $this->send($this->transport); + } + + //We suppose that character encoding of strings is UTF-8 on PHP script. + protected function txtConvert($string) + { + return mb_convert_encoding($string, 'ISO-8859-1', 'UTF-8'); + } + + protected function recipientFilename($transport) + { + return $transport->recipients . '_' . mt_rand() . '.tmp'; + } +} diff --git a/src/Scores/Stat/Op.php b/src/Scores/Stat/Op.php new file mode 100644 index 0000000..f3650ba --- /dev/null +++ b/src/Scores/Stat/Op.php @@ -0,0 +1,237 @@ + array( + array( + 'table' => 'jo.bodacc_detail', + 'columnsTotal' => array('COUNT(*) as Nb'), + 'where' => array( + 'idSirenage={id}', + 'dateUpdate BETWEEN "{begin}" AND "{end}"', + ), + 'group' => array(), + 'order' => array(), + ), + ), + 'annonce' => array( + array( + 'table' => 'jo.annonces', + 'columnsTotal' => array('COUNT(*) as Nb'), + 'where' => array( + 'idSaisie={id}', + 'source IN ("JS","TS","GC","PC") AND (dateInsert BETWEEN "{begin}" AND "{end}" OR dateUpdate BETWEEN "{begin}" AND "{end}")', + ), + 'group' => array(), + 'order' => array(), + ), + ), + 'asso' => array( + array( + 'table' => 'jo.asso', + 'columnsTotal' => array('COUNT(*) as Nb'), + 'columnsCsv' => array('*'), + 'where' => array( + 'idSirenage={id}', + 'dateUpdate BETWEEN "{begin}" AND "{end}"', + ), + 'group' => array(), + 'order' => array(), + ) + ), + 'dir' => array( + array( + 'table' => 'jo.rncs_dirigeants', + 'columnsTotal' => array('COUNT(*) as Nb'), + 'columnsCsv' => array('*'), + 'where' => array( + 'idSirenage={id}', + 'dateUpdate BETWEEN "{begin}" AND "{end}"', + ), + 'group' => array(), + 'order' => array(), + ), + ), + 'cac' => array( + array( + 'table' => 'jo.bodacc_dirigeants', + 'columnsTotal' => array('COUNT(*) as Nb'), + 'columnsCsv' => array('*'), + 'where' => array( + 'idSirenage={id}', + 'dateUpdate BETWEEN "{begin}" AND "{end}"', + ), + 'group' => array(), + 'order' => array(), + ), + ), + 'boamp' => array( + array( + 'table' => 'jo.boamp_lots', + 'columnsTotal' => array('COUNT(*) as Nb'), + 'where' => array( + 'idSirenage={id}', + 'dateUpdate BETWEEN "{begin}" AND "{end}"', + ), + 'group' => array(), + 'order' => array(), + ), + array( + 'table' => 'jo.boamp_detail', + 'columnsTotal' => array('COUNT(*) as Nb'), + 'where' => array( + 'idSirenage={id}', + 'dateUpdate BETWEEN "{begin}" AND "{end}"', + ), + 'group' => array(), + 'order' => array(), + ), + ), + 'client' => array( + array( + 'table' => 'jo.sirenage_clients', + 'columnsTotal' => array('COUNT(*) as Nb'), + 'where' => array( + 'idSirenage={id}', + 'dateUpdate BETWEEN "{begin}" AND "{end}"', + ), + 'group' => array(), + 'order' => array(), + ), + ), + 'marque' => array( + array( + 'table' => 'bopi.marques', + 'columnsTotal' => array('COUNT(*) as Nb'), + 'columnsCsv' => array('*'), + 'where' => array( + 'idSirenage={id}', + 'dateUpdate BETWEEN "{begin}" AND "{end}"', + ), + 'group' => array(), + 'order' => array(), + ), + ), + 'lien' => array( + array( + 'table' => 'jo.liens2', + 'columnsTotal' => array('COUNT(*) as Nb'), + 'where' => array( + 'idInsert={id} AND dateInsert BETWEEN "{begin}" AND "{end}" OR + idUpdate={id} AND dateUpdate BETWEEN "{begin}" AND "{end}" OR + idSuppr={id} AND dateSuppr BETWEEN "{begin}" AND "{end}"', + ), + 'group' => array(), + 'order' => array(), + ), + array( + 'table' => 'jo.liensRef', + 'columnsTotal' => array('COUNT(*) as Nb'), + 'where' => array( + 'idInsert={id} AND dateInsert BETWEEN "{begin}" AND "{end}" OR + idUpdate={id} AND dateUpdate BETWEEN "{begin}" AND "{end}" OR + idSuppr={id} AND dateSuppr BETWEEN "{begin}" AND "{end}"', + ), + 'group' => array(), + 'order' => array(), + ), + array( + 'table' => 'jo.liensDoc', + 'columnsTotal' => array('COUNT(*) as Nb'), + 'where' => array( + 'idInsert={id}', + 'dateInsert BETWEEN "{begin}" AND "{end}"', + ), + 'group' => array(), + 'order' => array(), + ), + ), + 'bilansaisie' => array( + array( + 'table' => 'jo.bilans_user', + 'columnsTotal' => array('COUNT(*) as Nb'), + 'where' => array( + 'idUtilisateur={id} AND dateAction BETWEEN "{begin}" AND "{end}"', + ), + 'group' => array(), + 'order' => array(), + ), + ), + 'tourisme' => array( + array( + 'table' => 'jo.tourisme', + 'columnsTotal' => array('COUNT(*) as Nb'), + 'where' => array( + 'idSirenage={id}', + 'dateUpdate BETWEEN "{begin}" AND "{end}"', + ), + 'group' => array(), + 'order' => array(), + ), + ), + ); + + protected $category; + protected $user; + protected $begin; + protected $end; + protected $db; + + public function __construct($category, $user, $dateBegin, $dateEnd = null) + { + $this->category = $category; + $this->user = $user; + $this->begin = $dateBegin.' 00:00:00'; + $this->end = $dateBegin.' 23:59:59'; + if ($dateEnd !== null) { + $this->end = $dateEnd.' 23:59:59'; + } + + $this->db = Zend_Db_Table_Abstract::getDefaultAdapter(); + } + + public function total() + { + $config = $this->sql[$this->category]; + + $nb = 0; + foreach ($config as $param) { + $sql = $this->db->select()->from($param['table'], $param['columnsTotal']); + foreach ($param['where'] as $where) { + $where = preg_replace('/\{id\}/', $this->user, $where); + $where = preg_replace('/\{begin\}/', $this->begin, $where); + $where = preg_replace('/\{end\}/', $this->end, $where); + $sql->where($where); + } + $this->db->setFetchMode(Zend_Db::FETCH_OBJ); + $result = $this->db->fetchRow($sql); + if ($result !== null) { + $nb = $nb + $result->Nb; + } + } + + return $nb; + } + + public function csv() + { + $config = $this->sql[$this->category]; + + foreach ($config as $param) { + $sql = $this->db->select()->from($param['table'], $param['columnsCSV']); + foreach ($param['where'] as $where) { + $where = preg_replace('/\{id\}/', $this->user, $where); + $where = preg_replace('/\{begin\}/', $this->begin, $where); + $where = preg_replace('/\{end\}/', $this->end, $where); + $sql->where($where); + } + $this->db->setFetchMode(Zend_Db::FETCH_OBJ); + $result = $this->db->fetchRow($sql); + if ($result !== null) { + + } + } + + } + +} \ No newline at end of file diff --git a/src/Scores/Surveillance/File.php b/src/Scores/Surveillance/File.php new file mode 100644 index 0000000..a5e065e --- /dev/null +++ b/src/Scores/Surveillance/File.php @@ -0,0 +1,90 @@ +delimiter = ','; + if (null !== $delimiter) { + $this->delimiter = $delimiter; + } + } + + /** + * Check file header + * @param string $file + * @return boolean|array + */ + public function checkHeader($file) + { + $row = 0; + $error = array(); + if (($handle = fopen($file, 'r')) !== false) { + while (($data = fgetcsv($handle, 0, $this->delimiter, '"')) !== false) { + $num = count($data); + //First line + if ($row == 0) { + //Detect key + foreach ( $this->header as $key ) { + for ( $c=0; $c < $num; $c++ ) { + if ( $key == strtolower($data[$c]) ) { + $this->position[$key] = $c; + } + } + } + break; + } + $row++; + } + fclose($handle); + } + if ( count($this->position) > 0 ) { + $tabKey = array_keys($this->position); + foreach( $this->headerRequired as $key) { + if ( !in_array($key, $tabKey) ) { + return false; + } + } + return $tabKey; + } + return false; + } + + public function setCmd(){} + + public function loadLines(){} + + + +} \ No newline at end of file diff --git a/src/Scores/Upload/Handler.php b/src/Scores/Upload/Handler.php new file mode 100644 index 0000000..b3c50aa --- /dev/null +++ b/src/Scores/Upload/Handler.php @@ -0,0 +1,1393 @@ + 'The uploaded file exceeds the upload_max_filesize directive in php.ini', + 2 => 'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form', + 3 => 'The uploaded file was only partially uploaded', + 4 => 'No file was uploaded', + 6 => 'Missing a temporary folder', + 7 => 'Failed to write file to disk', + 8 => 'A PHP extension stopped the file upload', + 'post_max_size' => 'The uploaded file exceeds the post_max_size directive in php.ini', + 'max_file_size' => 'File is too big', + 'min_file_size' => 'File is too small', + 'accept_file_types' => 'Filetype not allowed', + 'max_number_of_files' => 'Maximum number of files exceeded', + 'max_width' => 'Image exceeds maximum width', + 'min_width' => 'Image requires a minimum width', + 'max_height' => 'Image exceeds maximum height', + 'min_height' => 'Image requires a minimum height', + 'abort' => 'File upload aborted', + 'image_resize' => 'Failed to resize image' + ); + + protected $image_objects = array(); + + public function __construct($options = null, $initialize = true, $error_messages = null) { + $this->response = array(); + $this->options = array( + 'script_url' => $this->get_full_url().'/'.$this->basename($this->get_server_var('SCRIPT_NAME')), + 'upload_dir' => dirname($this->get_server_var('SCRIPT_FILENAME')).'/files/', + 'upload_url' => $this->get_full_url().'/files/', + 'input_stream' => 'php://input', + 'user_dirs' => false, + 'mkdir_mode' => 0755, + 'param_name' => 'files', + // Set the following option to 'POST', if your server does not support + // DELETE requests. This is a parameter sent to the client: + 'delete_type' => 'DELETE', + 'access_control_allow_origin' => '*', + 'access_control_allow_credentials' => false, + 'access_control_allow_methods' => array( + 'OPTIONS', + 'HEAD', + 'GET', + 'POST', + 'PUT', + 'PATCH', + 'DELETE' + ), + 'access_control_allow_headers' => array( + 'Content-Type', + 'Content-Range', + 'Content-Disposition' + ), + // By default, allow redirects to the referer protocol+host: + 'redirect_allow_target' => '/^'.preg_quote( + parse_url($this->get_server_var('HTTP_REFERER'), PHP_URL_SCHEME) + .'://' + .parse_url($this->get_server_var('HTTP_REFERER'), PHP_URL_HOST) + .'/', // Trailing slash to not match subdomains by mistake + '/' // preg_quote delimiter param + ).'/', + // Enable to provide file downloads via GET requests to the PHP script: + // 1. Set to 1 to download files via readfile method through PHP + // 2. Set to 2 to send a X-Sendfile header for lighttpd/Apache + // 3. Set to 3 to send a X-Accel-Redirect header for nginx + // If set to 2 or 3, adjust the upload_url option to the base path of + // the redirect parameter, e.g. '/files/'. + 'download_via_php' => false, + // Read files in chunks to avoid memory limits when download_via_php + // is enabled, set to 0 to disable chunked reading of files: + 'readfile_chunk_size' => 10 * 1024 * 1024, // 10 MiB + // Defines which files can be displayed inline when downloaded: + 'inline_file_types' => '/\.(gif|jpe?g|png)$/i', + // Defines which files (based on their names) are accepted for upload: + 'accept_file_types' => '/.+$/i', + // The php.ini settings upload_max_filesize and post_max_size + // take precedence over the following max_file_size setting: + 'max_file_size' => null, + 'min_file_size' => 1, + // The maximum number of files for the upload directory: + 'max_number_of_files' => null, + // Defines which files are handled as image files: + 'image_file_types' => '/\.(gif|jpe?g|png)$/i', + // Use exif_imagetype on all files to correct file extensions: + 'correct_image_extensions' => false, + // Image resolution restrictions: + 'max_width' => null, + 'max_height' => null, + 'min_width' => 1, + 'min_height' => 1, + // Set the following option to false to enable resumable uploads: + 'discard_aborted_uploads' => true, + // Set to 0 to use the GD library to scale and orient images, + // set to 1 to use imagick (if installed, falls back to GD), + // set to 2 to use the ImageMagick convert binary directly: + 'image_library' => 1, + // Uncomment the following to define an array of resource limits + // for imagick: + /* + 'imagick_resource_limits' => array( + imagick::RESOURCETYPE_MAP => 32, + imagick::RESOURCETYPE_MEMORY => 32 + ), + */ + // Command or path for to the ImageMagick convert binary: + 'convert_bin' => 'convert', + // Uncomment the following to add parameters in front of each + // ImageMagick convert call (the limit constraints seem only + // to have an effect if put in front): + /* + 'convert_params' => '-limit memory 32MiB -limit map 32MiB', + */ + // Command or path for to the ImageMagick identify binary: + 'identify_bin' => 'identify', + 'image_versions' => array( + // The empty image version key defines options for the original image: + '' => array( + // Automatically rotate images based on EXIF meta data: + 'auto_orient' => true + ), + // Uncomment the following to create medium sized images: + /* + 'medium' => array( + 'max_width' => 800, + 'max_height' => 600 + ), + */ + 'thumbnail' => array( + // Uncomment the following to use a defined directory for the thumbnails + // instead of a subdirectory based on the version identifier. + // Make sure that this directory doesn't allow execution of files if you + // don't pose any restrictions on the type of uploaded files, e.g. by + // copying the .htaccess file from the files directory for Apache: + //'upload_dir' => dirname($this->get_server_var('SCRIPT_FILENAME')).'/thumb/', + //'upload_url' => $this->get_full_url().'/thumb/', + // Uncomment the following to force the max + // dimensions and e.g. create square thumbnails: + //'crop' => true, + 'max_width' => 80, + 'max_height' => 80 + ) + ), + 'print_response' => true + ); + if ($options) { + $this->options = $options + $this->options; + } + if ($error_messages) { + $this->error_messages = $error_messages + $this->error_messages; + } + if ($initialize) { + $this->initialize(); + } + } + + protected function initialize() { + switch ($this->get_server_var('REQUEST_METHOD')) { + case 'OPTIONS': + case 'HEAD': + $this->head(); + break; + case 'GET': + $this->get($this->options['print_response']); + break; + case 'PATCH': + case 'PUT': + case 'POST': + $this->post($this->options['print_response']); + break; + case 'DELETE': + $this->delete($this->options['print_response']); + break; + default: + $this->header('HTTP/1.1 405 Method Not Allowed'); + } + } + + protected function get_full_url() { + $https = !empty($_SERVER['HTTPS']) && strcasecmp($_SERVER['HTTPS'], 'on') === 0 || + !empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && + strcasecmp($_SERVER['HTTP_X_FORWARDED_PROTO'], 'https') === 0; + return + ($https ? 'https://' : 'http://'). + (!empty($_SERVER['REMOTE_USER']) ? $_SERVER['REMOTE_USER'].'@' : ''). + (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : ($_SERVER['SERVER_NAME']. + ($https && $_SERVER['SERVER_PORT'] === 443 || + $_SERVER['SERVER_PORT'] === 80 ? '' : ':'.$_SERVER['SERVER_PORT']))). + substr($_SERVER['SCRIPT_NAME'],0, strrpos($_SERVER['SCRIPT_NAME'], '/')); + } + + protected function get_user_id() { + @session_start(); + return session_id(); + } + + protected function get_user_path() { + if ($this->options['user_dirs']) { + return $this->get_user_id().'/'; + } + return ''; + } + + protected function get_upload_path($file_name = null, $version = null) { + $file_name = $file_name ? $file_name : ''; + if (empty($version)) { + $version_path = ''; + } else { + $version_dir = @$this->options['image_versions'][$version]['upload_dir']; + if ($version_dir) { + return $version_dir.$this->get_user_path().$file_name; + } + $version_path = $version.'/'; + } + return $this->options['upload_dir'].$this->get_user_path() + .$version_path.$file_name; + } + + protected function get_query_separator($url) { + return strpos($url, '?') === false ? '?' : '&'; + } + + protected function get_download_url($file_name, $version = null, $direct = false) { + if (!$direct && $this->options['download_via_php']) { + $url = $this->options['script_url'] + .$this->get_query_separator($this->options['script_url']) + .$this->get_singular_param_name() + .'='.rawurlencode($file_name); + if ($version) { + $url .= '&version='.rawurlencode($version); + } + return $url.'&download=1'; + } + if (empty($version)) { + $version_path = ''; + } else { + $version_url = @$this->options['image_versions'][$version]['upload_url']; + if ($version_url) { + return $version_url.$this->get_user_path().rawurlencode($file_name); + } + $version_path = rawurlencode($version).'/'; + } + return $this->options['upload_url'].$this->get_user_path() + .$version_path.rawurlencode($file_name); + } + + protected function set_additional_file_properties($file) { + $file->deleteUrl = $this->options['script_url'] + .$this->get_query_separator($this->options['script_url']) + .$this->get_singular_param_name() + .'='.rawurlencode($file->name); + $file->deleteType = $this->options['delete_type']; + if ($file->deleteType !== 'DELETE') { + $file->deleteUrl .= '&_method=DELETE'; + } + if ($this->options['access_control_allow_credentials']) { + $file->deleteWithCredentials = true; + } + } + + // Fix for overflowing signed 32 bit integers, + // works for sizes up to 2^32-1 bytes (4 GiB - 1): + protected function fix_integer_overflow($size) { + if ($size < 0) { + $size += 2.0 * (PHP_INT_MAX + 1); + } + return $size; + } + + protected function get_file_size($file_path, $clear_stat_cache = false) { + if ($clear_stat_cache) { + if (version_compare(PHP_VERSION, '5.3.0') >= 0) { + clearstatcache(true, $file_path); + } else { + clearstatcache(); + } + } + return $this->fix_integer_overflow(filesize($file_path)); + } + + protected function is_valid_file_object($file_name) { + $file_path = $this->get_upload_path($file_name); + if (is_file($file_path) && $file_name[0] !== '.') { + return true; + } + return false; + } + + protected function get_file_object($file_name) { + if ($this->is_valid_file_object($file_name)) { + $file = new \stdClass(); + $file->name = $file_name; + $file->size = $this->get_file_size( + $this->get_upload_path($file_name) + ); + $file->url = $this->get_download_url($file->name); + foreach ($this->options['image_versions'] as $version => $options) { + if (!empty($version)) { + if (is_file($this->get_upload_path($file_name, $version))) { + $file->{$version.'Url'} = $this->get_download_url( + $file->name, + $version + ); + } + } + } + $this->set_additional_file_properties($file); + return $file; + } + return null; + } + + protected function get_file_objects($iteration_method = 'get_file_object') { + $upload_dir = $this->get_upload_path(); + if (!is_dir($upload_dir)) { + return array(); + } + return array_values(array_filter(array_map( + array($this, $iteration_method), + scandir($upload_dir) + ))); + } + + protected function count_file_objects() { + return count($this->get_file_objects('is_valid_file_object')); + } + + protected function get_error_message($error) { + return isset($this->error_messages[$error]) ? + $this->error_messages[$error] : $error; + } + + public function get_config_bytes($val) { + $val = trim($val); + $last = strtolower($val[strlen($val)-1]); + $val = (int)$val; + switch ($last) { + case 'g': + $val *= 1024; + case 'm': + $val *= 1024; + case 'k': + $val *= 1024; + } + return $this->fix_integer_overflow($val); + } + + protected function validate($uploaded_file, $file, $error, $index) { + if ($error) { + $file->error = $this->get_error_message($error); + return false; + } + $content_length = $this->fix_integer_overflow( + (int)$this->get_server_var('CONTENT_LENGTH') + ); + $post_max_size = $this->get_config_bytes(ini_get('post_max_size')); + if ($post_max_size && ($content_length > $post_max_size)) { + $file->error = $this->get_error_message('post_max_size'); + return false; + } + if (!preg_match($this->options['accept_file_types'], $file->name)) { + $file->error = $this->get_error_message('accept_file_types'); + return false; + } + if ($uploaded_file && is_uploaded_file($uploaded_file)) { + $file_size = $this->get_file_size($uploaded_file); + } else { + $file_size = $content_length; + } + if ($this->options['max_file_size'] && ( + $file_size > $this->options['max_file_size'] || + $file->size > $this->options['max_file_size']) + ) { + $file->error = $this->get_error_message('max_file_size'); + return false; + } + if ($this->options['min_file_size'] && + $file_size < $this->options['min_file_size']) { + $file->error = $this->get_error_message('min_file_size'); + return false; + } + if (is_int($this->options['max_number_of_files']) && + ($this->count_file_objects() >= $this->options['max_number_of_files']) && + // Ignore additional chunks of existing files: + !is_file($this->get_upload_path($file->name))) { + $file->error = $this->get_error_message('max_number_of_files'); + return false; + } + $max_width = @$this->options['max_width']; + $max_height = @$this->options['max_height']; + $min_width = @$this->options['min_width']; + $min_height = @$this->options['min_height']; + if (($max_width || $max_height || $min_width || $min_height) + && preg_match($this->options['image_file_types'], $file->name)) { + list($img_width, $img_height) = $this->get_image_size($uploaded_file); + + // If we are auto rotating the image by default, do the checks on + // the correct orientation + if ( + @$this->options['image_versions']['']['auto_orient'] && + function_exists('exif_read_data') && + ($exif = @exif_read_data($uploaded_file)) && + (((int) @$exif['Orientation']) >= 5) + ) { + $tmp = $img_width; + $img_width = $img_height; + $img_height = $tmp; + unset($tmp); + } + + } + if (!empty($img_width)) { + if ($max_width && $img_width > $max_width) { + $file->error = $this->get_error_message('max_width'); + return false; + } + if ($max_height && $img_height > $max_height) { + $file->error = $this->get_error_message('max_height'); + return false; + } + if ($min_width && $img_width < $min_width) { + $file->error = $this->get_error_message('min_width'); + return false; + } + if ($min_height && $img_height < $min_height) { + $file->error = $this->get_error_message('min_height'); + return false; + } + } + return true; + } + + protected function upcount_name_callback($matches) { + $index = isset($matches[1]) ? ((int)$matches[1]) + 1 : 1; + $ext = isset($matches[2]) ? $matches[2] : ''; + return ' ('.$index.')'.$ext; + } + + protected function upcount_name($name) { + return preg_replace_callback( + '/(?:(?: \(([\d]+)\))?(\.[^.]+))?$/', + array($this, 'upcount_name_callback'), + $name, + 1 + ); + } + + protected function get_unique_filename($file_path, $name, $size, $type, $error, + $index, $content_range) { + while(is_dir($this->get_upload_path($name))) { + $name = $this->upcount_name($name); + } + // Keep an existing filename if this is part of a chunked upload: + $uploaded_bytes = $this->fix_integer_overflow((int)$content_range[1]); + while (is_file($this->get_upload_path($name))) { + if ($uploaded_bytes === $this->get_file_size( + $this->get_upload_path($name))) { + break; + } + $name = $this->upcount_name($name); + } + return $name; + } + + protected function fix_file_extension($file_path, $name, $size, $type, $error, + $index, $content_range) { + // Add missing file extension for known image types: + if (strpos($name, '.') === false && + preg_match('/^image\/(gif|jpe?g|png)/', $type, $matches)) { + $name .= '.'.$matches[1]; + } + if ($this->options['correct_image_extensions'] && + function_exists('exif_imagetype')) { + switch (@exif_imagetype($file_path)){ + case IMAGETYPE_JPEG: + $extensions = array('jpg', 'jpeg'); + break; + case IMAGETYPE_PNG: + $extensions = array('png'); + break; + case IMAGETYPE_GIF: + $extensions = array('gif'); + break; + } + // Adjust incorrect image file extensions: + if (!empty($extensions)) { + $parts = explode('.', $name); + $extIndex = count($parts) - 1; + $ext = strtolower(@$parts[$extIndex]); + if (!in_array($ext, $extensions)) { + $parts[$extIndex] = $extensions[0]; + $name = implode('.', $parts); + } + } + } + return $name; + } + + protected function trim_file_name($file_path, $name, $size, $type, $error, + $index, $content_range) { + // Remove path information and dots around the filename, to prevent uploading + // into different directories or replacing hidden system files. + // Also remove control characters and spaces (\x00..\x20) around the filename: + $name = trim($this->basename(stripslashes($name)), ".\x00..\x20"); + // Use a timestamp for empty filenames: + if (!$name) { + $name = str_replace('.', '-', microtime(true)); + } + return $name; + } + + protected function get_file_name($file_path, $name, $size, $type, $error, + $index, $content_range) { + $name = $this->trim_file_name($file_path, $name, $size, $type, $error, + $index, $content_range); + return $this->get_unique_filename( + $file_path, + $this->fix_file_extension($file_path, $name, $size, $type, $error, + $index, $content_range), + $size, + $type, + $error, + $index, + $content_range + ); + } + + protected function get_scaled_image_file_paths($file_name, $version) { + $file_path = $this->get_upload_path($file_name); + if (!empty($version)) { + $version_dir = $this->get_upload_path(null, $version); + if (!is_dir($version_dir)) { + mkdir($version_dir, $this->options['mkdir_mode'], true); + } + $new_file_path = $version_dir.'/'.$file_name; + } else { + $new_file_path = $file_path; + } + return array($file_path, $new_file_path); + } + + protected function gd_get_image_object($file_path, $func, $no_cache = false) { + if (empty($this->image_objects[$file_path]) || $no_cache) { + $this->gd_destroy_image_object($file_path); + $this->image_objects[$file_path] = $func($file_path); + } + return $this->image_objects[$file_path]; + } + + protected function gd_set_image_object($file_path, $image) { + $this->gd_destroy_image_object($file_path); + $this->image_objects[$file_path] = $image; + } + + protected function gd_destroy_image_object($file_path) { + $image = (isset($this->image_objects[$file_path])) ? $this->image_objects[$file_path] : null ; + return $image && imagedestroy($image); + } + + protected function gd_imageflip($image, $mode) { + if (function_exists('imageflip')) { + return imageflip($image, $mode); + } + $new_width = $src_width = imagesx($image); + $new_height = $src_height = imagesy($image); + $new_img = imagecreatetruecolor($new_width, $new_height); + $src_x = 0; + $src_y = 0; + switch ($mode) { + case '1': // flip on the horizontal axis + $src_y = $new_height - 1; + $src_height = -$new_height; + break; + case '2': // flip on the vertical axis + $src_x = $new_width - 1; + $src_width = -$new_width; + break; + case '3': // flip on both axes + $src_y = $new_height - 1; + $src_height = -$new_height; + $src_x = $new_width - 1; + $src_width = -$new_width; + break; + default: + return $image; + } + imagecopyresampled( + $new_img, + $image, + 0, + 0, + $src_x, + $src_y, + $new_width, + $new_height, + $src_width, + $src_height + ); + return $new_img; + } + + protected function gd_orient_image($file_path, $src_img) { + if (!function_exists('exif_read_data')) { + return false; + } + $exif = @exif_read_data($file_path); + if ($exif === false) { + return false; + } + $orientation = (int)@$exif['Orientation']; + if ($orientation < 2 || $orientation > 8) { + return false; + } + switch ($orientation) { + case 2: + $new_img = $this->gd_imageflip( + $src_img, + defined('IMG_FLIP_VERTICAL') ? IMG_FLIP_VERTICAL : 2 + ); + break; + case 3: + $new_img = imagerotate($src_img, 180, 0); + break; + case 4: + $new_img = $this->gd_imageflip( + $src_img, + defined('IMG_FLIP_HORIZONTAL') ? IMG_FLIP_HORIZONTAL : 1 + ); + break; + case 5: + $tmp_img = $this->gd_imageflip( + $src_img, + defined('IMG_FLIP_HORIZONTAL') ? IMG_FLIP_HORIZONTAL : 1 + ); + $new_img = imagerotate($tmp_img, 270, 0); + imagedestroy($tmp_img); + break; + case 6: + $new_img = imagerotate($src_img, 270, 0); + break; + case 7: + $tmp_img = $this->gd_imageflip( + $src_img, + defined('IMG_FLIP_VERTICAL') ? IMG_FLIP_VERTICAL : 2 + ); + $new_img = imagerotate($tmp_img, 270, 0); + imagedestroy($tmp_img); + break; + case 8: + $new_img = imagerotate($src_img, 90, 0); + break; + default: + return false; + } + $this->gd_set_image_object($file_path, $new_img); + return true; + } + + protected function gd_create_scaled_image($file_name, $version, $options) { + if (!function_exists('imagecreatetruecolor')) { + error_log('Function not found: imagecreatetruecolor'); + return false; + } + list($file_path, $new_file_path) = + $this->get_scaled_image_file_paths($file_name, $version); + $type = strtolower(substr(strrchr($file_name, '.'), 1)); + switch ($type) { + case 'jpg': + case 'jpeg': + $src_func = 'imagecreatefromjpeg'; + $write_func = 'imagejpeg'; + $image_quality = isset($options['jpeg_quality']) ? + $options['jpeg_quality'] : 75; + break; + case 'gif': + $src_func = 'imagecreatefromgif'; + $write_func = 'imagegif'; + $image_quality = null; + break; + case 'png': + $src_func = 'imagecreatefrompng'; + $write_func = 'imagepng'; + $image_quality = isset($options['png_quality']) ? + $options['png_quality'] : 9; + break; + default: + return false; + } + $src_img = $this->gd_get_image_object( + $file_path, + $src_func, + !empty($options['no_cache']) + ); + $image_oriented = false; + if (!empty($options['auto_orient']) && $this->gd_orient_image( + $file_path, + $src_img + )) { + $image_oriented = true; + $src_img = $this->gd_get_image_object( + $file_path, + $src_func + ); + } + $max_width = $img_width = imagesx($src_img); + $max_height = $img_height = imagesy($src_img); + if (!empty($options['max_width'])) { + $max_width = $options['max_width']; + } + if (!empty($options['max_height'])) { + $max_height = $options['max_height']; + } + $scale = min( + $max_width / $img_width, + $max_height / $img_height + ); + if ($scale >= 1) { + if ($image_oriented) { + return $write_func($src_img, $new_file_path, $image_quality); + } + if ($file_path !== $new_file_path) { + return copy($file_path, $new_file_path); + } + return true; + } + if (empty($options['crop'])) { + $new_width = $img_width * $scale; + $new_height = $img_height * $scale; + $dst_x = 0; + $dst_y = 0; + $new_img = imagecreatetruecolor($new_width, $new_height); + } else { + if (($img_width / $img_height) >= ($max_width / $max_height)) { + $new_width = $img_width / ($img_height / $max_height); + $new_height = $max_height; + } else { + $new_width = $max_width; + $new_height = $img_height / ($img_width / $max_width); + } + $dst_x = 0 - ($new_width - $max_width) / 2; + $dst_y = 0 - ($new_height - $max_height) / 2; + $new_img = imagecreatetruecolor($max_width, $max_height); + } + // Handle transparency in GIF and PNG images: + switch ($type) { + case 'gif': + case 'png': + imagecolortransparent($new_img, imagecolorallocate($new_img, 0, 0, 0)); + case 'png': + imagealphablending($new_img, false); + imagesavealpha($new_img, true); + break; + } + $success = imagecopyresampled( + $new_img, + $src_img, + $dst_x, + $dst_y, + 0, + 0, + $new_width, + $new_height, + $img_width, + $img_height + ) && $write_func($new_img, $new_file_path, $image_quality); + $this->gd_set_image_object($file_path, $new_img); + return $success; + } + + protected function imagick_get_image_object($file_path, $no_cache = false) { + if (empty($this->image_objects[$file_path]) || $no_cache) { + $this->imagick_destroy_image_object($file_path); + $image = new \Imagick(); + if (!empty($this->options['imagick_resource_limits'])) { + foreach ($this->options['imagick_resource_limits'] as $type => $limit) { + $image->setResourceLimit($type, $limit); + } + } + $image->readImage($file_path); + $this->image_objects[$file_path] = $image; + } + return $this->image_objects[$file_path]; + } + + protected function imagick_set_image_object($file_path, $image) { + $this->imagick_destroy_image_object($file_path); + $this->image_objects[$file_path] = $image; + } + + protected function imagick_destroy_image_object($file_path) { + $image = (isset($this->image_objects[$file_path])) ? $this->image_objects[$file_path] : null ; + return $image && $image->destroy(); + } + + protected function imagick_orient_image($image) { + $orientation = $image->getImageOrientation(); + $background = new \ImagickPixel('none'); + switch ($orientation) { + case \imagick::ORIENTATION_TOPRIGHT: // 2 + $image->flopImage(); // horizontal flop around y-axis + break; + case \imagick::ORIENTATION_BOTTOMRIGHT: // 3 + $image->rotateImage($background, 180); + break; + case \imagick::ORIENTATION_BOTTOMLEFT: // 4 + $image->flipImage(); // vertical flip around x-axis + break; + case \imagick::ORIENTATION_LEFTTOP: // 5 + $image->flopImage(); // horizontal flop around y-axis + $image->rotateImage($background, 270); + break; + case \imagick::ORIENTATION_RIGHTTOP: // 6 + $image->rotateImage($background, 90); + break; + case \imagick::ORIENTATION_RIGHTBOTTOM: // 7 + $image->flipImage(); // vertical flip around x-axis + $image->rotateImage($background, 270); + break; + case \imagick::ORIENTATION_LEFTBOTTOM: // 8 + $image->rotateImage($background, 270); + break; + default: + return false; + } + $image->setImageOrientation(\imagick::ORIENTATION_TOPLEFT); // 1 + return true; + } + + protected function imagick_create_scaled_image($file_name, $version, $options) { + list($file_path, $new_file_path) = + $this->get_scaled_image_file_paths($file_name, $version); + $image = $this->imagick_get_image_object( + $file_path, + !empty($options['crop']) || !empty($options['no_cache']) + ); + if ($image->getImageFormat() === 'GIF') { + // Handle animated GIFs: + $images = $image->coalesceImages(); + foreach ($images as $frame) { + $image = $frame; + $this->imagick_set_image_object($file_name, $image); + break; + } + } + $image_oriented = false; + if (!empty($options['auto_orient'])) { + $image_oriented = $this->imagick_orient_image($image); + } + $new_width = $max_width = $img_width = $image->getImageWidth(); + $new_height = $max_height = $img_height = $image->getImageHeight(); + if (!empty($options['max_width'])) { + $new_width = $max_width = $options['max_width']; + } + if (!empty($options['max_height'])) { + $new_height = $max_height = $options['max_height']; + } + if (!($image_oriented || $max_width < $img_width || $max_height < $img_height)) { + if ($file_path !== $new_file_path) { + return copy($file_path, $new_file_path); + } + return true; + } + $crop = !empty($options['crop']); + if ($crop) { + $x = 0; + $y = 0; + if (($img_width / $img_height) >= ($max_width / $max_height)) { + $new_width = 0; // Enables proportional scaling based on max_height + $x = ($img_width / ($img_height / $max_height) - $max_width) / 2; + } else { + $new_height = 0; // Enables proportional scaling based on max_width + $y = ($img_height / ($img_width / $max_width) - $max_height) / 2; + } + } + $success = $image->resizeImage( + $new_width, + $new_height, + isset($options['filter']) ? $options['filter'] : \imagick::FILTER_LANCZOS, + isset($options['blur']) ? $options['blur'] : 1, + $new_width && $new_height // fit image into constraints if not to be cropped + ); + if ($success && $crop) { + $success = $image->cropImage( + $max_width, + $max_height, + $x, + $y + ); + if ($success) { + $success = $image->setImagePage($max_width, $max_height, 0, 0); + } + } + $type = strtolower(substr(strrchr($file_name, '.'), 1)); + switch ($type) { + case 'jpg': + case 'jpeg': + if (!empty($options['jpeg_quality'])) { + $image->setImageCompression(\imagick::COMPRESSION_JPEG); + $image->setImageCompressionQuality($options['jpeg_quality']); + } + break; + } + if (!empty($options['strip'])) { + $image->stripImage(); + } + return $success && $image->writeImage($new_file_path); + } + + protected function imagemagick_create_scaled_image($file_name, $version, $options) { + list($file_path, $new_file_path) = + $this->get_scaled_image_file_paths($file_name, $version); + $resize = @$options['max_width'] + .(empty($options['max_height']) ? '' : 'X'.$options['max_height']); + if (!$resize && empty($options['auto_orient'])) { + if ($file_path !== $new_file_path) { + return copy($file_path, $new_file_path); + } + return true; + } + $cmd = $this->options['convert_bin']; + if (!empty($this->options['convert_params'])) { + $cmd .= ' '.$this->options['convert_params']; + } + $cmd .= ' '.escapeshellarg($file_path); + if (!empty($options['auto_orient'])) { + $cmd .= ' -auto-orient'; + } + if ($resize) { + // Handle animated GIFs: + $cmd .= ' -coalesce'; + if (empty($options['crop'])) { + $cmd .= ' -resize '.escapeshellarg($resize.'>'); + } else { + $cmd .= ' -resize '.escapeshellarg($resize.'^'); + $cmd .= ' -gravity center'; + $cmd .= ' -crop '.escapeshellarg($resize.'+0+0'); + } + // Make sure the page dimensions are correct (fixes offsets of animated GIFs): + $cmd .= ' +repage'; + } + if (!empty($options['convert_params'])) { + $cmd .= ' '.$options['convert_params']; + } + $cmd .= ' '.escapeshellarg($new_file_path); + exec($cmd, $output, $error); + if ($error) { + error_log(implode('\n', $output)); + return false; + } + return true; + } + + protected function get_image_size($file_path) { + if ($this->options['image_library']) { + if (extension_loaded('imagick')) { + $image = new \Imagick(); + try { + if (@$image->pingImage($file_path)) { + $dimensions = array($image->getImageWidth(), $image->getImageHeight()); + $image->destroy(); + return $dimensions; + } + return false; + } catch (\Exception $e) { + error_log($e->getMessage()); + } + } + if ($this->options['image_library'] === 2) { + $cmd = $this->options['identify_bin']; + $cmd .= ' -ping '.escapeshellarg($file_path); + exec($cmd, $output, $error); + if (!$error && !empty($output)) { + // image.jpg JPEG 1920x1080 1920x1080+0+0 8-bit sRGB 465KB 0.000u 0:00.000 + $infos = preg_split('/\s+/', substr($output[0], strlen($file_path))); + $dimensions = preg_split('/x/', $infos[2]); + return $dimensions; + } + return false; + } + } + if (!function_exists('getimagesize')) { + error_log('Function not found: getimagesize'); + return false; + } + return @getimagesize($file_path); + } + + protected function create_scaled_image($file_name, $version, $options) { + if ($this->options['image_library'] === 2) { + return $this->imagemagick_create_scaled_image($file_name, $version, $options); + } + if ($this->options['image_library'] && extension_loaded('imagick')) { + return $this->imagick_create_scaled_image($file_name, $version, $options); + } + return $this->gd_create_scaled_image($file_name, $version, $options); + } + + protected function destroy_image_object($file_path) { + if ($this->options['image_library'] && extension_loaded('imagick')) { + return $this->imagick_destroy_image_object($file_path); + } + } + + protected function is_valid_image_file($file_path) { + if (!preg_match($this->options['image_file_types'], $file_path)) { + return false; + } + if (function_exists('exif_imagetype')) { + return @exif_imagetype($file_path); + } + $image_info = $this->get_image_size($file_path); + return $image_info && $image_info[0] && $image_info[1]; + } + + protected function handle_image_file($file_path, $file) { + $failed_versions = array(); + foreach ($this->options['image_versions'] as $version => $options) { + if ($this->create_scaled_image($file->name, $version, $options)) { + if (!empty($version)) { + $file->{$version.'Url'} = $this->get_download_url( + $file->name, + $version + ); + } else { + $file->size = $this->get_file_size($file_path, true); + } + } else { + $failed_versions[] = $version ? $version : 'original'; + } + } + if (count($failed_versions)) { + $file->error = $this->get_error_message('image_resize') + .' ('.implode($failed_versions, ', ').')'; + } + // Free memory: + $this->destroy_image_object($file_path); + } + + protected function handle_file_upload($uploaded_file, $name, $size, $type, $error, + $index = null, $content_range = null) { + $file = new \stdClass(); + $file->name = $this->get_file_name($uploaded_file, $name, $size, $type, $error, + $index, $content_range); + $file->size = $this->fix_integer_overflow((int)$size); + $file->type = $type; + if ($this->validate($uploaded_file, $file, $error, $index)) { + $this->handle_form_data($file, $index); + $upload_dir = $this->get_upload_path(); + if (!is_dir($upload_dir)) { + mkdir($upload_dir, $this->options['mkdir_mode'], true); + } + $file_path = $this->get_upload_path($file->name); + $append_file = $content_range && is_file($file_path) && + $file->size > $this->get_file_size($file_path); + if ($uploaded_file && is_uploaded_file($uploaded_file)) { + // multipart/formdata uploads (POST method uploads) + if ($append_file) { + file_put_contents( + $file_path, + fopen($uploaded_file, 'r'), + FILE_APPEND + ); + } else { + move_uploaded_file($uploaded_file, $file_path); + } + } else { + // Non-multipart uploads (PUT method support) + file_put_contents( + $file_path, + fopen($this->options['input_stream'], 'r'), + $append_file ? FILE_APPEND : 0 + ); + } + $file_size = $this->get_file_size($file_path, $append_file); + if ($file_size === $file->size) { + $file->url = $this->get_download_url($file->name); + if ($this->is_valid_image_file($file_path)) { + $this->handle_image_file($file_path, $file); + } + } else { + $file->size = $file_size; + if (!$content_range && $this->options['discard_aborted_uploads']) { + unlink($file_path); + $file->error = $this->get_error_message('abort'); + } + } + $this->set_additional_file_properties($file); + } + return $file; + } + + protected function readfile($file_path) { + $file_size = $this->get_file_size($file_path); + $chunk_size = $this->options['readfile_chunk_size']; + if ($chunk_size && $file_size > $chunk_size) { + $handle = fopen($file_path, 'rb'); + while (!feof($handle)) { + echo fread($handle, $chunk_size); + @ob_flush(); + @flush(); + } + fclose($handle); + return $file_size; + } + return readfile($file_path); + } + + protected function body($str) { + echo $str; + } + + protected function header($str) { + header($str); + } + + protected function get_upload_data($id) { + return @$_FILES[$id]; + } + + protected function get_post_param($id) { + return @$_POST[$id]; + } + + protected function get_query_param($id) { + return @$_GET[$id]; + } + + protected function get_server_var($id) { + return @$_SERVER[$id]; + } + + protected function handle_form_data($file, $index) { + // Handle form data, e.g. $_POST['description'][$index] + } + + protected function get_version_param() { + return $this->basename(stripslashes($this->get_query_param('version'))); + } + + protected function get_singular_param_name() { + return substr($this->options['param_name'], 0, -1); + } + + protected function get_file_name_param() { + $name = $this->get_singular_param_name(); + return $this->basename(stripslashes($this->get_query_param($name))); + } + + protected function get_file_names_params() { + $params = $this->get_query_param($this->options['param_name']); + if (!$params) { + return null; + } + foreach ($params as $key => $value) { + $params[$key] = $this->basename(stripslashes($value)); + } + return $params; + } + + protected function get_file_type($file_path) { + switch (strtolower(pathinfo($file_path, PATHINFO_EXTENSION))) { + case 'jpeg': + case 'jpg': + return 'image/jpeg'; + case 'png': + return 'image/png'; + case 'gif': + return 'image/gif'; + default: + return ''; + } + } + + protected function download() { + switch ($this->options['download_via_php']) { + case 1: + $redirect_header = null; + break; + case 2: + $redirect_header = 'X-Sendfile'; + break; + case 3: + $redirect_header = 'X-Accel-Redirect'; + break; + default: + return $this->header('HTTP/1.1 403 Forbidden'); + } + $file_name = $this->get_file_name_param(); + if (!$this->is_valid_file_object($file_name)) { + return $this->header('HTTP/1.1 404 Not Found'); + } + if ($redirect_header) { + return $this->header( + $redirect_header.': '.$this->get_download_url( + $file_name, + $this->get_version_param(), + true + ) + ); + } + $file_path = $this->get_upload_path($file_name, $this->get_version_param()); + // Prevent browsers from MIME-sniffing the content-type: + $this->header('X-Content-Type-Options: nosniff'); + if (!preg_match($this->options['inline_file_types'], $file_name)) { + $this->header('Content-Type: application/octet-stream'); + $this->header('Content-Disposition: attachment; filename="'.$file_name.'"'); + } else { + $this->header('Content-Type: '.$this->get_file_type($file_path)); + $this->header('Content-Disposition: inline; filename="'.$file_name.'"'); + } + $this->header('Content-Length: '.$this->get_file_size($file_path)); + $this->header('Last-Modified: '.gmdate('D, d M Y H:i:s T', filemtime($file_path))); + $this->readfile($file_path); + } + + protected function send_content_type_header() { + $this->header('Vary: Accept'); + if (strpos($this->get_server_var('HTTP_ACCEPT'), 'application/json') !== false) { + $this->header('Content-type: application/json'); + } else { + $this->header('Content-type: text/plain'); + } + } + + protected function send_access_control_headers() { + $this->header('Access-Control-Allow-Origin: '.$this->options['access_control_allow_origin']); + $this->header('Access-Control-Allow-Credentials: ' + .($this->options['access_control_allow_credentials'] ? 'true' : 'false')); + $this->header('Access-Control-Allow-Methods: ' + .implode(', ', $this->options['access_control_allow_methods'])); + $this->header('Access-Control-Allow-Headers: ' + .implode(', ', $this->options['access_control_allow_headers'])); + } + + public function generate_response($content, $print_response = true) { + $this->response = $content; + if ($print_response) { + $json = json_encode($content); + $redirect = stripslashes($this->get_post_param('redirect')); + if ($redirect && preg_match($this->options['redirect_allow_target'], $redirect)) { + $this->header('Location: '.sprintf($redirect, rawurlencode($json))); + return; + } + $this->head(); + if ($this->get_server_var('HTTP_CONTENT_RANGE')) { + $files = isset($content[$this->options['param_name']]) ? + $content[$this->options['param_name']] : null; + if ($files && is_array($files) && is_object($files[0]) && $files[0]->size) { + $this->header('Range: 0-'.( + $this->fix_integer_overflow((int)$files[0]->size) - 1 + )); + } + } + $this->body($json); + } + return $content; + } + + public function get_response () { + return $this->response; + } + + public function head() { + $this->header('Pragma: no-cache'); + $this->header('Cache-Control: no-store, no-cache, must-revalidate'); + $this->header('Content-Disposition: inline; filename="files.json"'); + // Prevent Internet Explorer from MIME-sniffing the content-type: + $this->header('X-Content-Type-Options: nosniff'); + if ($this->options['access_control_allow_origin']) { + $this->send_access_control_headers(); + } + $this->send_content_type_header(); + } + + public function get($print_response = true) { + if ($print_response && $this->get_query_param('download')) { + return $this->download(); + } + $file_name = $this->get_file_name_param(); + if ($file_name) { + $response = array( + $this->get_singular_param_name() => $this->get_file_object($file_name) + ); + } else { + $response = array( + $this->options['param_name'] => $this->get_file_objects() + ); + } + return $this->generate_response($response, $print_response); + } + + public function post($print_response = true) { + if ($this->get_query_param('_method') === 'DELETE') { + return $this->delete($print_response); + } + $upload = $this->get_upload_data($this->options['param_name']); + // Parse the Content-Disposition header, if available: + $content_disposition_header = $this->get_server_var('HTTP_CONTENT_DISPOSITION'); + $file_name = $content_disposition_header ? + rawurldecode(preg_replace( + '/(^[^"]+")|("$)/', + '', + $content_disposition_header + )) : null; + // Parse the Content-Range header, which has the following form: + // Content-Range: bytes 0-524287/2000000 + $content_range_header = $this->get_server_var('HTTP_CONTENT_RANGE'); + $content_range = $content_range_header ? + preg_split('/[^0-9]+/', $content_range_header) : null; + $size = $content_range ? $content_range[3] : null; + $files = array(); + if ($upload) { + if (is_array($upload['tmp_name'])) { + // param_name is an array identifier like "files[]", + // $upload is a multi-dimensional array: + foreach ($upload['tmp_name'] as $index => $value) { + $files[] = $this->handle_file_upload( + $upload['tmp_name'][$index], + $file_name ? $file_name : $upload['name'][$index], + $size ? $size : $upload['size'][$index], + $upload['type'][$index], + $upload['error'][$index], + $index, + $content_range + ); + } + } else { + // param_name is a single object identifier like "file", + // $upload is a one-dimensional array: + $files[] = $this->handle_file_upload( + isset($upload['tmp_name']) ? $upload['tmp_name'] : null, + $file_name ? $file_name : (isset($upload['name']) ? + $upload['name'] : null), + $size ? $size : (isset($upload['size']) ? + $upload['size'] : $this->get_server_var('CONTENT_LENGTH')), + isset($upload['type']) ? + $upload['type'] : $this->get_server_var('CONTENT_TYPE'), + isset($upload['error']) ? $upload['error'] : null, + null, + $content_range + ); + } + } + $response = array($this->options['param_name'] => $files); + return $this->generate_response($response, $print_response); + } + + public function delete($print_response = true) { + $file_names = $this->get_file_names_params(); + if (empty($file_names)) { + $file_names = array($this->get_file_name_param()); + } + $response = array(); + foreach ($file_names as $file_name) { + $file_path = $this->get_upload_path($file_name); + $success = is_file($file_path) && $file_name[0] !== '.' && unlink($file_path); + if ($success) { + foreach ($this->options['image_versions'] as $version => $options) { + if (!empty($version)) { + $file = $this->get_upload_path($file_name, $version); + if (is_file($file)) { + unlink($file); + } + } + } + } + $response[$file_name] = $success; + } + return $this->generate_response($response, $print_response); + } + + protected function basename($filepath, $suffix = null) { + $splited = preg_split('/\//', rtrim ($filepath, '/ ')); + return substr(basename('X'.$splited[count($splited)-1], $suffix), 1); + } +} \ No newline at end of file diff --git a/src/Scores/Validate/IpInNetwork.php b/src/Scores/Validate/IpInNetwork.php new file mode 100644 index 0000000..ed770e2 --- /dev/null +++ b/src/Scores/Validate/IpInNetwork.php @@ -0,0 +1,632 @@ +Accepts an array with options. Also adds the error messages to the parent's message templates.

    + * @example

    List of allow options and their use: + * $options argument must be an array and allows two key/value pairs for this class and passes on any remaining + * values to the parent class Zend_Validate_Ip. If key 'network' exists it will pass on the value to method + * setNetworkNotation and for key 'throw' to setThrow4Notation.

    + * @see Zend_Validate_Ip::__construct() + * @see Scores_Validate_IpInNetwork::setNetworkNotation() + * @see Scores_Validate_IpInNetwork::setThrow4Notation() + * @param array $options + * @return void + */ + public function __construct($options = array()) + { + if (!empty($options) && is_array($options)) { + if (array_key_exists('throw', $options)) { + $this->setThrow4Notation($options['throw']); + unset($options['throw']); + } + if (array_key_exists('network', $options)) { + $this->setNetworkNotation($options['network']); + unset($options['network']); + } + } + + $this->setMessages(array()); + + parent::__construct($options); + } + + /** + * (non-PHPdoc) + * @see Zend_Validate_Abstract::setMessages() + */ + public function setMessages(array $messages) + { + $newMessages = array( + self::MISSING_NETWORK => 'No valid network has been given to validate against', + self::INVALID_NETWORK => 'The network is not an accepted format', + self::NOT_IN_NETWORK => "The ip '%value%' does not match the provided 32 network", + self::LOW_IN_NETWORK => "The ip '%value%' is lower in range than the provided network", + self::HIGH_IN_NETWORK => "The ip '%value%' is higher in range than the provided network", + ); + + foreach ($newMessages as $messageKey => $messageString) { + if (!isset($this->_messageTemplates[$messageKey])) { + $this->_messageTemplates[$messageKey] = $messageString; + } elseif (!empty($messages) && array_key_exists($messageKey, $messages)) { + $this->_messageTemplates[$messageKey] = $messages[$messageKey]; + unset($messages[$messageKey]); + } + } + + empty($messages) || parent::setMessages($messages) ; + + return $this; + } + + /** + * (non-PHPdoc) + * @see Zend_Validate_Ip::isValid() + */ + public function isValid($value) + { + if (true === parent::isValid($value)) { + $notation = $this->_getNotation(); + if (!empty($notation)) { + // a valid notation has been set + $network = $this->_getNetwork(); + if (!empty($network)) { + if (true === $this->_validateIpInNetwork($value)) { + return true; + } + } else { + if (true === $this->_validateIpInRange($value)) { + return true; + } + } + // NOTE: Errors are only available in regards to the value (ip address) and not the network/netmask (notation) + $errors = $this->getErrors(); + if (empty($errors)) { + $this->_error(self::NOT_IN_NETWORK); + } + } else { + $this->_error(self::MISSING_NETWORK); + } + } + + return false; + } + + /** + * Validates the IP in a given network + * + * @since Version 0.1.36 + * @version 0.1.36 2012/01/14 16:34:00 CST + * @author aw + * @desc

    Takes the CIDR and network (IP) address and validates the given IP address against it. Sets the appropriate + * errors if the IP is not a match for the network.

    + * @param string $ip + * @return bool + */ + protected function _validateIpInNetwork($ip) + { + $netmask = $this->getCidr(); + $network = $this->_getNetwork(); + + // lets get this out of the way first + if (32 === $netmask) { + // this network has to match the IP + if ($network === $ip) { + return true; + } else { + $this->_error(self::NOT_IN_NETWORK); + return false; + } + } + + // get the unsigned integers for the IP and network address + $ip_addr_uDec = $this->_makeUnsignedAddress($ip); + $lNetwork_uDec = $this->_makeUnsignedAddress($network); + + // let verify the IP against the lower end of the range + if ($ip_addr_uDec < $lNetwork_uDec) { + // the ip is below the network range + $this->_error(self::LOW_IN_NETWORK); + return false; + } + + // well then, finally verify the IP against the uppoer end of the range + + // add the decimal representation of the netmask to the network IP + $netmask_uDec1 = $netmask < 31 ? pow(2, (32-$netmask)) - 1 : 1 ; + $netmask_uDec = pow(2, 32-$netmask) - 1 ; + $uNetwork_uDec = $lNetwork_uDec + $netmask_uDec; + + if ($ip_addr_uDec > $uNetwork_uDec) { + // the ip is above the network range + $this->_error(self::HIGH_IN_NETWORK); + return false; + } + + return true; + } + + /** + * Validates the IP in a given range + * + * @since Version 0.1.36 + * @version 0.1.36 2012/01/16 13:06:00 CST + * @author aw + * @desc

    Takes the "from" and "to" (IP) address and validates the given IP address against it. Sets the appropriate + * errors if the IP is not within the defined range.

    + * @param string $ip + * @return bool + */ + protected function _validateIpInRange($ip) + { + $uInt_Ip = $this->_makeUnsignedAddress($ip); + + if (is_numeric($this->_rangeFrom) && $uInt_Ip >= $this->_rangeFrom) { + if ($uInt_Ip <= $this->_rangeTo) { + return true; + } elseif (is_numeric($this->_rangeTo)) { + $this->_error(self::HIGH_IN_NETWORK); + return false; + } + } elseif (is_numeric($this->_rangeFrom)) { + $this->_error(self::LOW_IN_NETWORK); + return false; + } + + $this->_error(self::MISSING_NETWORK); + return false; + } + + /** + * Set the network (notation) to the properties + * + * @since Version 0.1.36 + * @version 0.1.36 2012/01/14 13:43:00 CST + * @author aw + * @desc

    The network is usually a notation with a network/netmask combination. The method uses two methods to validate + * the netmask and the network address. If the notation is a range fromIPAddress-toIPAddress the netmask and network address + * are ignored. The isValid() will then attempt to validate the value within the range and not the network segment.

    + * string $notation network/address (128.0.0.0/24) (128.0.0.0/255.255.255.0) or (128.0.0.0-128.0.0.255) + * @return object|false Awd_Validate_IpInNetwork + */ + public function setNetworkNotation($notation) + { + $network = false !== strpos($notation, '/') ? $this->_evaluateNetmask($notation) : false ; + if (false !== $network) { + // a valid CIDR/netmask has been found + if (true === parent::isValid($network)) { + if ($this->_validateNetwork($network)) { + $this->_network = $network; + $this->_notation = $notation; + + return $this; + } + } else { + $this->_invalidNetwork(__LINE__); + } + } elseif (false !== strpos($notation, '-')) { + // the notation is looking like a from-to IP range + if (true === $this->_validateRange($notation)) { + $this->_notation = $notation; + + return $this; + } + } + + return false; + } + + /** + * Sets the value for _throw property + * + * @since Version 0.1.36 + * @version 0.1.35 2012/01/17 08:23:00 CST + * @author aw + * @desc

    The value determines if the application will throw an exception or trigger an E_USER_WARNING if + * an error was found in the submitted network notation. The default is false.

    + * @throws E_USER_WARNING if the argument is not of type bool + * bool $throw + * @return object Awd_Validate_IpInNetwork + */ + public function setThrow4Notation($throw = false) + { + if (!is_bool($throw)) { + $msg = '[AWD] Programming error: The argument is not a boolean value'; + trigger_error($msg, E_USER_WARNING); + } + + + $this->_throw = $throw; + return $this; + } + + /** + * Gets the value for _throw property + * + * @since Version 0.1.36 + * @version 0.1.35 2012/01/17 08:27:00 CST + * @author aw + * @desc

    The value determines if the application will throw an exception or trigger an E_USER_WARNING if + * an error was found in the submitted network notation. The default is false.

    + * @return bool + */ + public function getThrow4Notation() + { + return (bool) $this->_throw; + } + + /** + * Gets the network (notation) as it has been set if valid + * + * @since Version 0.1.36 + * @version 0.1.36 2012/01/14 16:08:00 CST + * @author aw + * @desc

    If empty the network (notation) was either not set or not valid. Hence, this method can be used to + * verify if setting a network range or notation was successful with the constructor.

    + * @return string + */ + public function getNetworkNotation() + { + return (string) $this->_getNotation(); + } + + /** + * Protected method to gets the network (notation) as it has been set if valid + * + * @since Version 0.1.36 + * @version 0.1.36 2012/01/14 16:08:00 CST + * @author aw + * @desc

    Note that the notation is only available when it passed the internal validation. Internally (protected) + * the network represents the network (IP) address whereas the notation is the full string as set when is valid. + * The notation is a representation of network range or network/mask. This method essentially returns internally + * (protected) the same result as the public method getNetworkNotation().

    + * @return string|null + */ + protected function _getNotation() + { + return empty($this->_notation) ? null : (string) $this->_notation ; + } + + /** + * Gets the network address from the notation if a valid address and mask has been set + * + * @since Version 0.1.36 + * @version 0.1.36 2012/01/14 16:18:00 CST + * @author aw + * @desc

    Note that internally (protected) the network represents the network (IP) address extracted from the + * "network notation", i.e. a representation of network range or network/mask. If the notation was not valid or a + * network range has been set this value will be empty.

    + * @return string + */ + protected function _getNetwork() + { + return (string) $this->_network; + } + + /** + * Gets the CIDR from the notation if a valid address and mask has been set + * + * @since Version 0.1.36 + * @version 0.1.36 2012/01/14 16:26:00 CST + * @author aw + * @desc

    The CIDR has been extracted from the "network notation", i.e. a representation of network/mask or + * network/CIDR. If the notation was not valid or a network range has been set this value will be empty.

    + * @return int + */ + public function getCidr() + { + return (int) $this->_cidr; + } + + /** + * Evaluates the netmask from a notation + * + * @since Version 0.1.36 + * @version 0.1.36 2012/01/15 10:12:00 CST + * @author aw + * @desc

    The notation is usually set as a {network/CIDR} or {network/netmask} notation. This method examines + * the string following a slash. A CIDR mask will be verified for its number whereas a netmask is passed to + * another method _validateNetmask() for validation and if valid converted into a CIDR representation. In + * either case if the value is valid the remaining network (IP) address is returned or false on failure.

    + * @throws Calls method _invalidNetwork() when a failure is detected + * @param string $notation + * @return string|bool (false) + */ + protected function _evaluateNetmask($notation) + { + // split the notation in network and netmask information + list($network, $netmask) = explode('/', $notation, 2); + if (is_numeric($netmask)) { + // does look like a CIDR netmask + $between = new Zend_Validate_Between(array('min'=>1, 'max'=>32)); + if (true === $between->isValid($netmask)) { + $this->_cidr = (int) $netmask; + return $network; + } else { + $error_msgs = $between->getMessages(); + if (!empty($error_msgs) && is_array($error_msgs)) { + $msg = array_shift($error_msgs); + } else { + // fallback, should not really be an option + $msg = sprintf('The netmask [ %s ] is not a valid option', $netmask); + } + + // oops, this CIDR is not a valid range + return $this->_invalidNetwork(__LINE__.' - '.$msg); + } + } elseif (!empty($netmask)) { + // looks more like 32-bit (like 255.255.255.0) format + if (true === ($line = $this->_validateNetmask($netmask))) { + return $network; + } + + return $this->_invalidNetwork($line); + } + + return $this->_invalidNetwork(__LINE__); + } + + /** + * Validates a 32-bit netmask + * + * @since Version 0.1.36 + * @version 0.1.36 2012/01/16 10:34:00 CST + * @author aw + * @desc

    A netmask is a decimal representation of 32-bit string where the beginning sequence is a complete + * set of 1 (one) followed by a complete set of 0 (zero). If valid the netmask string will be a CIDR numeric + * value and set to the proected property _cidr. If not valid the returned value is the line plus the index if + * the failure is in one of the segments.

    + * @param string $netmask + * @return true|string + */ + protected function _validateNetmask($netmask) + { + $classes = explode('.', $netmask); + if (4 !== count($classes)) { + return __LINE__; + } + + $cidr = 0; + $end = false; + foreach ($classes as $index => $segment) { + if (!is_numeric($segment)) { + return __LINE__; + } elseif (0 === (int) $segment) { + $end = true; // all following segment have to be 0 (zero) as well + continue; + } + $matches = array(); + + // evaluate the binary representation of the segment + $bin = decbin($segment); + if (8 !== strlen($bin) || 0 === preg_match('/^([1]{1,8})([0]*)$/', decbin($segment), $matches)) { + if (8 !== strlen($bin)) { + // this segment is not a complete byte (8 bits) i.e. a value below 128 + return __LINE__.':'.++$index; // NOTE: Index begins at 0 (zero) + } + // this segment is a complete byte (8 bits), i.e. a value above 128, but not a valid binary mask (like 11110000) + return __LINE__.':'.++$index; // NOTE: Index begins at 0 (zero) + } elseif (true === $end) { + // a mask was found in the previous segment; therefore, this segment should be 0 (zero) + return __LINE__.':'.++$index; // NOTE: Index begins at 0 (zero) + } + $len = strlen($matches[1]); + if ($len < 8) { + $end = true; + } + $cidr += $len; + } + + $this->_cidr = $cidr; + return true; + } + + /** + * Validates the network address in a subnet notation + * + * @since Version 0.1.36 + * @version 0.1.36 2012/01/16 10:34:00 CST + * @author aw + * @desc

    The network address in a CIDR or subnet mask notation is the base of the assigned block. + * Because the size of the block is specified by the CIDR or subnet mask the base of a network address + * has to fit and match into the block size. This method evaluates the block size and then validates + * if the base of network address fits into the assigned block. If not valid the line plus the index + * of the failed segment is sent to method _invalidNetwork() triggering or throwing an error.

    + * @param string $network + * @return true|string + */ + protected function _validateNetwork($network) + { + $cidr = $this->getCidr(); + $class = $cidr / 8; + + // an integer indicates a classful (unicast) network + if (is_int($class)) { + $iClass = $class; + $maskBits = 0; + } else { + $iClass = (int) floor($class); + $maskBits = (int) 8 - ($cidr - ($iClass * 8)); + $hosts = (int) pow(2, $maskBits); // number of usable hosts in a subnet + } + + $segments = explode('.', $network); + // Note: $segments index begins at 0 (zero) and $iClass is the last complete segment in the netmask (8 bits (255)) + // It is irrelevant but just to clarify for $iClass: 1 = Class A, 2 = Class B, 3 = Class C + + $complete = false; + // check all segments following the last complete class and because we have to check for + // subnetting in the _follow_ class we do NOT add 1 to $iClass as the index in $segments + for ($index = $iClass; $index < 4; $index++) { + $subNetwork = (int) $segments[$index]; + + if (0 === $maskBits) { + // this class has no subnets (aka classful network) + // all 0 (zero) are expected as (sub)network numbers + if (0 !== $subNetwork) { + return $this->_invalidNetwork(__LINE__.':'.++$index); // NOTE: Index begins at 0 (zero) + } + continue; + } else { + // this class has subnets (aka a classless (subnetted) network) + if (true === $complete) { + // for all following networks 0 (zero) is expected as (sub)network number + if (0 !== $subNetwork) { + return $this->_invalidNetwork(__LINE__.':'.++$index); // NOTE: Index begins at 0 (zero) + } + continue; + } + $complete = true; + + // the (sub)network must be a fact or hosts(/subnets) + $block = $subNetwork / $hosts; + if (is_int($block)) { + // all clear + // NOTE: We do NOT return yet because we may have to verify any following segments + continue; + } else { + return $this->_invalidNetwork(__LINE__.':'.++$index.':'.$hosts); // NOTE: Index begins at 0 (zero) + } + } + } + + return true; + } + + /** + * Validates a network range with a "from-to" IP address notation + * + * @since Version 0.1.36 + * @version 0.1.35 2012/01/16 12:44:00 CST + * @author aw + * @desc

    A network range can be any difference (or equal) between two valid IP addresses. The method will even switch the + * values if the "to" is lower than the "from" address.

    + * @param string $range + * @return bool + */ + protected function _validateRange($range) + { + list($from, $to) = explode('-', $range); // Note: we do NOT care if more IP ranges have been set, i.e. the range would be invalid + + if (false === ($uInt_from = $this->_makeUnsignedAddress($from)) || false === ($uInt_to = $this->_makeUnsignedAddress($to))) { + return $this->_invalidNetwork(__LINE__); // at least one of the addresses is not a valid IP address + } + + if ($uInt_from <= $uInt_to) { + $this->_rangeFrom = $uInt_from; + $this->_rangeTo = $uInt_to; + } else { + // the range is not in the correct order + $this->_rangeFrom = $uInt_to; + $this->_rangeTo = $uInt_from; + } + + return true; + } + + /** + * Converts an IP address into an unsigned decimal number (see ATTENTION note for returned value) + * + * @since Version 0.1.36 + * @version 0.1.35 2012/01/16 12:31:00 CST + * @author aw + * @desc

    Uses php function ip2long() to convert the IP into a signed value first and then returns the value with + * sprintf($u). ATTENTION: Function sprintf returns this value as a string and typecasting will not produce the expected + * result for IP addresses above 128.0.0.0. Do not typecast this value to an integer!

    + * @param string $ip + * @return string + */ + private function _makeUnsignedAddress($ip) + { + if (false === ($ip_addr_long = ip2long($ip))) { + // not a valid IP address + return false; + } + + // Note ip2long creates signed integers + // a positive number means the address is in the lower half < 128 (0nnn nnnn.) + // a negative number means the address is in the upper half >= 128 (1nnn nnnn.) + // 127.255.255.255 = 2147483647 + // 128.0.0.1 = -2147483647 + // 128.0.0.0 = -2147483648 + + // convert to unsigned decimal number + return sprintf('%u', $ip_addr_long); + } + + /** + * Triggers an error warning or throws an exception + * + * @since Version 0.1.36 + * @version 0.1.36 2012/01/15 11:54:00 CST + * @author aw + * @desc

    The error message contains the argument which is usually the line where the error occured. The calling method + * may add additional information to the line number.

    + * @throws E_USER_WARNING If the _throw property is false (default) + * @throws Exception If the _throw property is true + * @param string|int $line + * @return bool (false) + */ + private function _invalidNetwork($line) + { + $error_msg = 'The provided network information is not a recognized format [#'.$line.']'; + $this->_error(self::INVALID_NETWORK, $error_msg); + $msg = '[SCORES] Application error: '.$error_msg; + if (false === $this->_throw) { + trigger_error($msg, E_USER_WARNING); + return false; + } else { + throw new Exception($msg); + } + } +} diff --git a/src/Scores/Validate/IpInNetwork.txt b/src/Scores/Validate/IpInNetwork.txt new file mode 100644 index 0000000..b7a6f2b --- /dev/null +++ b/src/Scores/Validate/IpInNetwork.txt @@ -0,0 +1,39 @@ +This validator class will test an IP against a provide network notation. The +network notation can be a network range, or network address with CIDR or 32-bit +decimal subnet mask notation. Note that the main validation method always uses +the CIDR notation, i.e a bitmask will be converted into a CIDR. + + +Examples for network notations +------------------------------ +Network Range: +************** +128.0.0.12-128.0.0.19 +true for all IP addresses inclusively in this range (i.e. from .12 to .19) + +CIDR notation: +************** +128.0.0.8/30 +block with 4 hosts +true for IP addresses from .8-.11 (i.e. .8, .9, .10, .11) + +Subnet mask notation: +********************* +128.0.0.8/255.255.255.252 +same as CIDR notation + +Special Notes: +-------------- +1) The network notation is validated, i.e. you have to pass a valid network and +CIDR or subnet mask combination. For the network range the two values must be +valid IP addresses. + +2) A CIDR notation of /32, subnet mask /255.255.255.255 or a range with two +equal addresses will match for one host, i.e. the result is true if the network +address or the range addresses are identical to the IP address + +3) The network notation or a range has to be set prior to calling isValid() as +is custom with all Zend validators. The notation can be set when instantiating +the object as an array and 'network' as the index. The setter method is +setNetworkNotation($notation) and expects a string as the argument. + \ No newline at end of file diff --git a/src/Scores/Wkhtml/Pdf.php b/src/Scores/Wkhtml/Pdf.php new file mode 100644 index 0000000..377b1e8 --- /dev/null +++ b/src/Scores/Wkhtml/Pdf.php @@ -0,0 +1,53 @@ +wkhtml = $c->profil->wkhtmltopdf->path; + } + + /** + * Défini les options supplémentaires à l'execution de wkhtmltopdf + * -n, --disable-javascript Do not allow webpages to run javascript. + * --disable-internal-links Do no make local links + * --disable-external-links Do no make links to remote web pages + * --user-style-sheet Specify a user style sheet, to load with every page. + * --print-media-type Use print media-type instead of screen. + * --header-left|right + * @param string $name + * @param string $value + */ + public function setOptions($name, $value = '') + { + $this->options[$name] = $value; + } + + /** + * Imprime un fichier HTML en PDF avec l'utilitaire wkhtmltopdf + * @param string $fileIn + * @param string $fileOut + * @return string Nom du fichier + */ + public function exec($fileIn, $fileOut = '') + { + if (empty($fileOut)) {$fileOut = str_replace('.html', '.pdf', $fileIn); } + if(file_exists($fileOut)){ unlink($fileOut); } + + $options = '--disable-internal-links'; + if ( count($this->options) ) + { + foreach ( $this->options as $name => $value ) + { + $options.= ' --'.$name; + if ($value!= '') $options.= ' "'.$value.'"'; + } + } + + $cmd = $this->wkhtml.' '.$options.' "'.$fileIn.'" "'.$fileOut.'"'; + exec( $cmd ); + return $fileOut; + } +} \ No newline at end of file diff --git a/src/Scores/Ws/Discover.php b/src/Scores/Ws/Discover.php new file mode 100644 index 0000000..82e6a1e --- /dev/null +++ b/src/Scores/Ws/Discover.php @@ -0,0 +1,84 @@ +serviceWsdl = $wsdl; + $this->serviceOptions = $options; + $this->setStructure(); + } + + public function getStructure() + { + return $this->serviceStructure; + } + + public function getStructureParam() + { + return $this->serviceStructureTypes; + } + + protected function setStructure() + { + $client = new Zend_Soap_Client( + $this->serviceWsdl, + $this->serviceOptions + ); + $this->serviceFunctions = $client->getFunctions(); + $this->serviceTypes = $client->getTypes(); + + foreach ($this->serviceFunctions as $func) { + $this->setFunction($func); + } + + foreach ($this->serviceTypes as $type) { + $this->setType($type); + } + } + + protected function setFunction($func) + { + if (preg_match('/[^\s]+\s([^\s]+)\((.*)\)/', $func, $matches)) { + $funcName = $matches[1]; + $funcParams = $matches[2]; + $this->serviceStructure[$funcName] = array(); + if (preg_match_all('/([^\s]+)\s([^\s]+),?/', $funcParams, $mParams)) { + $nbParams = count($mParams[0]); + for ($i=0;$i<$nbParams;$i++) { + $type = $mParams[1][$i]; + $name = $mParams[2][$i]; + $this->serviceStructure[$funcName][$i] = array( + 'name' => $name, + 'type' => $type + ); + } + } + } + } + + protected function setType($type) + { + $type = str_replace("\n", '', $type); + if (preg_match('/struct\s([^\s]+)\s\{(.*)\}$/m', $type, $matches)) { + $struct = trim($matches[1]); + $params = trim($matches[2]); + preg_match_all('/([^\s]+)\s([^\s]+);/', $params, $paramsMatches); + $nbParams = count($paramsMatches[0]); + $this->serviceStructureTypes[$struct] = array(); + for ($i=0; $i<$nbParams;$i++) { + $this->serviceStructureTypes[$struct][$i] = array( + 'name' => $paramsMatches[2][$i], + 'type' => $paramsMatches[1][$i], + ); + } + } + } +} diff --git a/src/Scores/Ws/Doc.php b/src/Scores/Ws/Doc.php new file mode 100644 index 0000000..943e6af --- /dev/null +++ b/src/Scores/Ws/Doc.php @@ -0,0 +1,181 @@ +serviceClass = $serviceClass; + $this->classmap = $classmap; + require_once $path . 'Service.php'; + $this->parseService(); + $this->parseTypes(); + } + + /** + * Retourne la liste des services et leurs paramètres + * @return array + */ + public function getServiceMethods() + { + return $this->serviceMethods; + } + + /** + * Retourne la liste des types de données et leurs paramètres + * @return array + */ + public function getServiceTypes() + { + return $this->serviceTypes; + } + + private function parseService() + { + $class = new Zend_Server_Reflection(); + $methods = $class->reflectClass($this->serviceClass) + ->getMethods(); + $methodsElement = array(); + foreach ($methods as $method) { + $prototype = null; + $maxNumArgumentsOfPrototype = -1; + foreach ($method->getPrototypes() as $tmpPrototype) { + $numParams = count($tmpPrototype->getParameters()); + if ($numParams > $maxNumArgumentsOfPrototype) { + $maxNumArgumentsOfPrototype = $numParams; + $prototype = $tmpPrototype; + } + } + + $paramsElement = array(); + foreach ($prototype->getParameters() as $param) { + $paramElement = array( + 'type' => $param->getType(), + 'name' => $param->getName(), + 'description' => $param->getDescription(), + + ); + if ($param->isOptional()) { + $paramElement['optional'] = $param->isOptional(); + $paramElement['defaultValue'] = $param->getDefaultValue(); + } + $paramsElement[] = $paramElement; + } + + $methodElement = array( + 'name' => $method->getName(), + 'desc' => $method->getDescription(), + 'params' => $paramsElement, + 'return' => $prototype->getReturnType(), + ); + + $methodsElement[] = $methodElement; + } + $this->serviceMethods = $methodsElement; + } + + private function parseTypes() + { + $typesElement = array(); + if (count($this->classmap)>0) { + foreach ($this->classmap as $className) { + $class = new ReflectionClass($className); + $paramsElement = array(); + foreach ($class->getProperties() as $property) { + if ($property->isPublic() && preg_match_all('/@var\s+([^\s]+)/m', $property->getDocComment(), $matches)) { + $name = $property->getName(); + $type = $matches[1][0]; + + /** + * Traitement éléments de documentation à placer dans le WSDL + * Supprime les retours chariots. + * Récupére les éléments de documentation + */ + $comment = ''; + $docBlock = preg_replace('/\n/', '', $property->getDocComment()); + if (preg_match('/\/\*\*(.+) \* @var\s+[^\s]+\s+(?:\*|@)/m', $docBlock, $docBlockMatches)) { + $comment.= preg_replace( + array('/\r/', '/\*/' ), + array('', ''), $docBlockMatches[1] + ); + } + + /** + * Traitement des @xsd (Provisoire) + * Définition des longueurs dans la documentation + * @xsd minLength=[\d]+ => (Longueur min = [\d]+) + * @xsd maxLength=[\d]+ => (Longueur max = [\d]+) + * @xsd enumeration=element,element + */ + if (preg_match_all('/@xsd\s+(minLength|maxLength)=([\d]+)\s+(?:\*|@)/m', $property->getDocComment(), $resMatches, PREG_SET_ORDER)) { + $comment.= '('; + $parcourCpt = 0; + foreach ($resMatches as $res) { + switch ($res[1]) { + case 'minLength': + $comment.= 'Longueur min = '.$res[2]; + break; + case 'maxLength': + $comment.= 'Longueur max = '.$res[2]; + break; + } + $parcourCpt++; + if ($parcourCpt>0 && $parcourCpt http://vhost/ref/fichier/ + * @ref mysql:titre:requete.sql + * => http://vhost/ref/table/ + */ + if (preg_match_all('/@ref\s+(fichier|mysql):(.*):(.*)\.(?:csv|sql)\s+(?:\*|@)/m', $property->getDocComment(), $refMatches, PREG_SET_ORDER)) { + $view = new Zend_View(); + $comment.= ', Référence(s) : '; + foreach ($refMatches as $ref) { + switch ($ref[1]) { + case 'fichier': + $urlFichier = $view->url(array( + 'controller' => 'ref', + 'action' => 'fichier', + 'q' => $ref[3], + ), null, true); + $comment.= ''.$ref[2].''; + break; + case 'mysql': + $urlMysql = $view->url(array( + 'controller' => 'ref', + 'action' => 'table', + 'q' => $ref[3], + ), null, true); + $comment.= ''.$ref[2].''; + break; + } + $comment.= ', '; + } + } + $paramElement = array( + 'name' => $name, + 'type' => $type, + 'description' => trim($comment) + ); + } + $paramsElement[] = $paramElement; + } + $typesElement[$className] = $paramsElement; + } + $this->serviceTypes = $typesElement; + } + } +} diff --git a/src/Scores/Ws/Exception.php b/src/Scores/Ws/Exception.php new file mode 100644 index 0000000..f12b749 --- /dev/null +++ b/src/Scores/Ws/Exception.php @@ -0,0 +1,4 @@ +setName('soapform'); + $this->setAction('/demo/requete'); + $this->setMethod('post'); + $this->addElement('text', 'siret', array( + 'filters' => array('StringTrim'), + 'validators' => array( + array('stringLength', false, array(9, 14)), + array('NotEmpty', true), + ), + 'label' => 'Siret : ', + 'required' => 'true', + ) + ); + $this->addElement('submit', 'submit', array( + 'label' => 'Envoyez', + )); + } +} diff --git a/src/Scores/Ws/Server.php b/src/Scores/Ws/Server.php new file mode 100644 index 0000000..89736fc --- /dev/null +++ b/src/Scores/Ws/Server.php @@ -0,0 +1,1102 @@ + "Afficher les anciens NAF", + 'NACE' => "Afficher les codes NACES", + 'NEWS' => "Afficher les news Google©", + 'MAPPY' => "Afficher les façades d'immeubles", + 'CARTES' => "Afficher les cartes et les plans", + 'VOIRSURV' => "Afficher les entités sous surveillances", + 'DEMANDEREF' => "Demande de référence par defaut", + 'RECHREF' => "Afficher le formulaire de recherche par référence", + ); + + /** + * List logs for facturation + * @var array + */ + protected $logs = array( + 'identite' => array( + 'label' => "Identité" + ), + 'liens' => array( + 'label' => "Liens Inter-Entreprise" + ), + 'etablissements' => array( + 'label' => "Etablissements" + ), + 'dirigeants' => array( + 'label' => "Dirigeants" + ), + 'annonces' => array( + 'label' => "Annonces légales", + ), + 'indiscore' => array( + 'label' => "Indiscore", + ), + 'indiscorep' => array( + 'label' => "Indiscore+", + ), + 'indiscore2' => array( + 'label' => "Rapport", + ), + 'indiscore2p' => array( + 'label' => "Rapport avec suivi", + ), + 'indiscore3' => array( + 'label' => "Rapport complet", + ), + 'indiscore3p' => array( + 'label' => "Rapport complet avec suivi", + ), + 'evenements' => array( + 'label' => "Modifications Insee", + ), + 'tva' => array( + 'label' => "Numéro de TVA intracommunautaire", + ), + 'infosreg' => array( + 'label' => "Informations réglementées", + ), + 'bourse' => array( + 'label' => "Information boursière" + ), + 'bilan' => array( + 'label' => "Liasse fiscale", + ), + 'sirenExiste' => array( + 'label' => "Controle du SIREN", + ), + 'ratios' => array( + 'label' => "Ratios", + ), + 'rapport1' => array( + 'label' => "Rapport complet 1", + ), + 'rapport2' => array( + 'label' => "Rapport complet 2", + ), + 'rapport3' => array( + 'label' => "Rapport complet 3", + ), + 'banque' => array( + 'label' => "Relations banquaires", + ), + 'competences' => array( + 'label' => "Competences territoriales", + ), + 'privdetail' => array( + 'label' => "Détails des privilèges", + ), + 'privcumul' => array( + 'label' => "Privilèges cumulés", + ), + 'conventions' => array( + 'label' => "Conventions collectives", + ), + 'marques' => array( + 'label' => "Marques déposés", + ), + 'kbis' => array( + 'label' => "Extrait RCS", + ), + 'dirigeantsop' => array( + 'label' => "Dirigeants opérationels", + ), + 'groupesarbo' => array( + 'label' => "Arborescence de groupes", + ), + 'groupeinfos' => array( + 'label' => "Informations groupe", + ), + 'valorisation' => array( + 'label' => "Valorisation", + ), + 'rnvp' => array( + 'label' => "Normalisation postale", + ), + ); + + /** + * List of error code send as SoapFault + * @var unknown_type + */ + public $listError = array( + '0000' => "Erreur indeterminé", + '0900' => "Identifiant ou mot de passe incorrect", + '0901' => "Accès WS non autorisé pour cet utilisateur", + '0902' => "Méthode non autorisée dans votre profil", + '0903' => "Période d'accès au service invalide", + '0904' => "Adresse IP Invalide", + '0905' => "Accès environnement de test non autorisé", + '0906' => "Erreur configuration utilisateur", + '1010' => "Siren invalide", + '1011' => "Identifiant invalide", + '1020' => "Siren inexistant", + '1021' => "Type d'identifiant inexistant", + '1030' => "Aucun résultat pour ce siren en base", + '3000' => "Service disponible", + '9000' => "Service S&D indisponible", + '9001' => "Service partenaire indisponible", + '9002' => "Méthode provisoirement indisponible", + '9003' => "Version du service désactivé", + '9004' => "Version du service inexistant", + '9010' => "Fichier indisponible", + '9020' => "Requête incorrecte", + ); + + /** + * PDO Connection with Doctrine + * @var \Doctrine\DBAL\Connection + */ + protected $conn; + + /** + * Logger + * @var \Monolog\Logger + */ + protected $logger; + + /** + * Server SOAP + * Document/Literal Wrapped - WS-I Compliant + */ + public function __construct() + { + $this->conn = Zend_Registry::get('doctrine'); + + if (Zend_Registry::isRegistered('logger')) { + $this->logger = Zend_Registry::get('logger'); + } + + $this->listeDroits = include APPLICATION_PATH . '/../library/Scores/Account/Access.php'; + $this->listeCategory = include APPLICATION_PATH . '/../library/Scores/Account/Category.php'; + } + + /** + * Send SoapFault with code and messade define + * @param string $code + * @throws SoapFault + */ + protected function sendError($code) + { + $message = 'Erreur inconnue'; + if (array_key_exists($code, $this->listError)) { + $message = $this->listError[$code]; + } + throw new SoapFault($code, $message); + exit; + } + + /** + * Enregistre l'appel utilisateur à une méthode + * @param $service + * @param $siret + * @param $ref + * @return void + */ + protected function wsLog($service, $siret = '', $ref = '') + { + //Is it a test + if ($this->User->clientTest=='Oui' || $this->User->typeCompte=='TEST') { + $test = 1; + } else { + $test = 0; + } + + $siren = 0; + if (strlen($siret) == 14) { + $siren = substr($siret, 0, 9); + $nic = substr($siret, 9, 5); + } elseif (strlen($siret) == 9) { + $siren = $siret; + $nic = ''; + } + + // Set data by default + $dataInsert = array( + 'login' => $this->User->login, + 'page' => $service, + 'params' => $ref, + 'idClient' => $this->User->idClient, + 'test' => $test, + 'actifInsee' => 0, + 'source' => 0, + 'raisonSociale' => '', + 'cp' => '', + 'ville' => '', + 'ipClient' => $this->User->ipConnexion, + ); + + $pageRS = array( + 'identite', + 'greffe_bilans', + 'greffe_actes', + 'liens', + 'dirigeants', + 'etablissements', + 'dirigeantsOp', + 'kbis', + 'indiscore', + 'indiscore2', + 'indiscore3', + 'rapport2', + 'rapport3' + ); + + if (intval($siren)!=0) { + $dataInsert['siren'] = $siren; + $dataInsert['nic'] = $nic; + } + + if (intval($siren)!=0 && in_array($service, $pageRS)) { + $qb = $this->conn->createQueryBuilder(); + $qb->select(array('e.siren', 'e.nic', 'e.actif', 'e.siege', 'e.raisonSociale', + 'e.adr_cp', 'e.adr_ville', 'e.source', 'COUNT(r.siren) AS nb')) + ->from('jo.etablissements', 'e') + ->where('e.siren = :siren')->setParameter('siren', $siren) + ->rightJoin('e', 'jo.rncs_entrep', 'r', 'e.siren = r.siren'); + + if (intval($siren) > 1000 && intval($nic) > 9) { + $qb->andWhere('e.nic = :nic')->setParameter('nic', $nic); + } elseif (intval($siren) == 0 && $ref > 0) { + $qb->andWhere('e.id = :id')->setParameter('id', $ref); + } elseif (intval($siren) > 1000) { + $qb->andWhere('e.siege = 1')->orderBy('e.actif', 'DESC')->orderBy('e.nic', 'DESC'); + } else { + return; + } + + try { + $stmt = $qb->execute(); + if ($stmt->rowCount() > 0) { + $result = $stmt->fetch(\PDO::FETCH_OBJ); + $dataInsert['raisonSociale'] = $result->raisonSociale; + $dataInsert['cp'] = $result->adr_cp; + $dataInsert['ville'] = $result->adr_ville; + $dataInsert['source'] = $result->source; + if ($result->actif == 0) { + $dataInsert['actifInsee'] = 0; + } elseif (intval($siren) > 1000) { + $dataInsert['actifInsee'] = 1; + if ($result->nb > 0) { + $dataInsert['source'] = 5; + } + } + } + } catch (\Doctrine\DBAL\DBALException $e) { + } + } + + try { + $this->conn->insert('sdv1.logs', $dataInsert); + } catch (\Doctrine\DBAL\DBALException $e) { + } + } + + /** + * Authenticate with SoapHeader, Optional (Authentication could be done by sending HTTP Basic header - see the doc) + * @param string $username + * @param string $password + * @throws SoapFault + */ + public function authenticate($username = null, $password = null) + { + if ($this->authenticated === false) { + if (empty($username)) { + /** + * @todo : Digest auth + */ + $this->authMethod = 'basic'; + $username = $_SERVER['PHP_AUTH_USER']; + $password = $_SERVER['PHP_AUTH_PW']; + } else { + /** + * Auth Header in client + * $ns = 'auth'; + * //Create our Auth Object to pass to the SOAP service with our values + * $auth = new StdClass(); + * $auth->username = 'yourlogin'; + * $auth->password = 'yourpassword'; + * $creds = new SoapVar($auth, SOAP_ENC_OBJECT); + * + * //The 2nd variable, 'authenticate' is a method that exists inside of the SOAP service (you must create it, see next example) + * $authenticate = new SoapHeader($ns, 'authenticate', $creds, false); + * + * $client->__setSoapHeaders($authenticate); + * + */ + $this->authMethod = 'soapheader'; + } + + /** + * With proxy get the original IP + * $request->getClientIp(true); + * Si IP Proxy regarder la valeur HTTP_X_FORWARDED_FOR + */ + $ip = $_SERVER['REMOTE_ADDR']; + if (isset($_SERVER['HTTP_X_FORWARDED_FOR']) && in_array($ip, $this->listProxyIp)) { + $ip = $_SERVER['HTTP_X_FORWARDED_FOR']; + } + + /** + * Lors d'une demande d'authentification depuis une application on garde l'IP en mémoire, + * c'est donc celle là qu'il faut utiliser. + */ + if ($this->authIp !== null) { + $ip = $this->authIp; + } + + /** + * Check authentication from the database + */ + $this->authenticated = $this->checkAuth($username, $password, $ip); + if ($this->authenticated === false) { + $this->sendError('0900'); + } elseif (is_string($this->authenticated)) { + $this->sendError($this->authenticated); + } + } + } + + /** + * Check permission + * @param string $perm + */ + protected function permission($perm) + { + if (!$this->checkPerm($perm)) { + $this->sendError('0902'); + } + } + + /** + * Check if user has the right to access WebService + * @throws SoapFault + */ + protected function checkAccesWS() + { + //Vérifier que l'utilisateur à le droit accesWS (clients/utilisateurs) + $accesWs = $this->User->accesWS; + if ($accesWs) { + $this->sendError('0901'); + } + } + + /** + * Check if the user has the right to acces this functionality + * @param string $perm + * @throws SoapFault + */ + protected function checkPerm($perm) + { + $output = false; + $droits = $this->User->droits; + if (is_array($droits)) { + if (in_array(strtolower($perm), $droits)) { + $output = true; + } + } else { + if (preg_match('/\b'.$perm.'\b/i', $droits)) { + $output = true; + } + } + + return $output; + } + + /** + * Check if the user could edit data + */ + protected function checkEdition() + { + if ($this->User->idClient == 1) { + return true; + } + + if ($this->checkPerm('edition')) { + return true; + } + + return false; + } + + + /** + * checkAuth + * @param string $login + * @param string $password + * @param string $ipConnexion + * @return mixed + */ + protected function checkAuth($login, $password, $ip) + { + if (empty($login)) { + $this->sendError('0900'); + } + + /** + * User information + */ + try { + $qb = $this->conn->createQueryBuilder(); + $qb->select(array( + 'u.login', 'u.id', 'u.email', 'u.password', 'u.idClient', 'u.typeCompte', 'u.actif', + 'u.filtre_ip', 'u.profil', 'u.civilite', 'u.nom', 'u.prenom', 'u.tel', 'u.fax', + 'u.mobile', 'u.pref', 'u.rechRefType', 'u.profil', 'u.nombreConnexions', + 'u.dateDerniereConnexion', 'u.droits', 'u.referenceParDefaut', 'u.nbReponses', 'u.lang', + 'u.formatMail', 'u.dateDebutCompte', 'u.dateFinCompte', 'u.accesWS', 'u.acceptationCGU', + 'c.droits AS droitsClients', 'c.test AS clientTest', 'c.typeScore', 'c.timeout', + 's.Service AS serviceCode', 'v.version')) + ->from('sdv1.utilisateurs', 'u') + ->join('u', 'sdv1.clients', 'c', 'u.idClient = c.id') + ->leftJoin('u', 'sdv1.utilisateurs_service', 's', 'u.login=s.login') + ->leftJoin('u', 'sdv1.clients_version', 'v', 'u.idClient=v.clientId') + ->where('u.actif = 1')->andWhere('u.deleted = 0')->andWhere("c.actif = 'Oui'"); + + /** + * Connexion avec login = email + */ + if (strstr($login, '@') !== false) { + $qb->andWhere('u.email = :email')->setParameter('email', $login); + } + /** + * Connexion standard + */ + else { + $qb->andWhere('u.login = :login')->setParameter('login', $login); + } + $stmt = $qb->execute(); + } catch (\Doctrine\DBAL\DBALException $e) { + } + + /** + * No user, deleted or disable + */ + if ($stmt->rowCount() == 0) { + return false; + } + + /** + * Multiple compte + */ + if ($stmt->rowCount() > 1) { + return '0906'; + } + + /** + * Get Data + */ + try { + $result = $stmt->fetch(\PDO::FETCH_OBJ); + } catch (\Doctrine\DBAL\DBALException $e) { + if ($this->logger != null) { + $this->logger->error("AUTH : ".$e->getMessage()); + } + return '0000'; + } + + /** + * Date de debut de compte + */ + if (!empty($result->dateDebutCompte) && $result->dateDebutCompte!='0000-00-00') { + $today = mktime(0, 0, 0, date('m'), date('d'), date('Y')); + $dateDebutCompte = mktime(0, 0, 0, substr($result->dateDebutCompte, 5, 2), substr($result->dateDebutCompte, 8, 2), substr($result->dateDebutCompte, 0, 4)); + if ($today < $dateDebutCompte) { + return '0903'; + } + } + + /** + * Date de fin de compte + */ + if (!empty($result->dateFinCompte) && $result->dateFinCompte!='0000-00-00') { + $today = mktime(0, 0, 0, date('m'), date('d'), date('Y')); + $dateFinCompte = mktime(0, 0, 0, substr($result->dateFinCompte, 5, 2), substr($result->dateFinCompte, 8, 2), substr($result->dateFinCompte, 0, 4)); + if ($today > $dateFinCompte) { + return '0903'; + } + } + + /** + * Service fallback + */ + if ($result->serviceCode === null) { + $result->serviceCode = 'DEFAULT'; + } + + /** + * Select authentication version + */ + if ($result->version == 2) { + $authResult = $this->authV2($result, $password, $ip); + } else { + $authResult = $this->authV1($result, $password, $ip); + } + + $this->authLog($result->login, $authResult, $ip); + + return $authResult; + } + + /** + * Authentification v1 + * @param object $userInfos + * @param string $password + * @param string $ip + * @return string|boolean + */ + protected function authV1($userInfos, $password, $ip) + { + /** + * Acces WS, block access to other apps + */ + if ($userInfos->accesWS == 1 && $userInfos->idClient != 1) { + // --- Webservice user don't need access to others apps + if (in_array($ip, $this->listApplicationIp)) { + return '0901'; + } elseif ($ip != '127.0.0.1') { + + // --- For customized version, check user is in the good service + $clients = include APPLICATION_PATH . '/../library/WsScore/Clients/ClientsConfig.php'; + $wsClients = array(); + foreach ($clients as $section => $params) { + if ($params['actif']) { + if (count($params['idClient']) > 0) { + foreach ($params['idClient'] as $idClient) { + $wsClients[$idClient] = $section; + } + } + } + } + if (array_key_exists($userInfos->idClient, $wsClients) && ($this->serviceClient === false + || strtolower($this->serviceClientName) != $wsClients[$userInfos->idClient])) { + return '0901'; + } + } + } + + /** + * Protect staging environment + * - No webservice access + * - Not in production + * - Not idClient 1 or 147 + */ + if (APPLICATION_ENV=='staging' && !in_array($userInfos->idClient, array(1, 147)) && $userInfos->accesWS==0) { + return '0905'; + } + + /** + * IP Validation + * Get an array of IP and IP range + * 192.168.3.5-192.68.3.10;192.168.3.*;192.168.3.10 + */ + + if (!in_array($ip, $this->listApplicationIp)) { + if (!empty($userInfos->filtre_ip)) { + $filtreIp = explode(';', trim($userInfos->filtre_ip, ';')); + if (count($filtreIp)>0) { + + // Extranet + if (substr($password, 0, 7)=='iponly:') { + $ipToValidate = substr($password, 7); + } + // WebService + else { + $ipToValidate = $ip; + } + + //Validation + $overallIpValidate = false; + foreach ($filtreIp as $filtre) { + if (strpos($filtre, '*')) { + $filtre = str_replace('*', '0', $filtre) . '-' . str_replace('*', '255', $filtre); + } + // Is it a range ? + if (strpos($filtre, '-')) { + $validateIp = new Scores_Validate_IpInNetwork(); + $validateIp->setNetworkNotation($filtre); + $overallIpValidate = $validateIp->isValid($ipToValidate); + } + // Ip only + else { + if ($filtre === $ipToValidate) { + $overallIpValidate = true; + } + } + // Break foreach + if ($overallIpValidate === true) { + break; + } + } + + // Exit with error + if ($overallIpValidate === false) { + return '0904'; + } + } + } + } + + // Check password with database informations + if ($userInfos->password == $password //password sent in clear + || md5($userInfos->password) == $password //password sent with md5 + || md5($userInfos->login.'|'.$userInfos->password) == $password //password sent concat with login and crypt by md5 + || substr($password, 0, 7) == 'iponly:' + ) { + + //Timeout + $timeout = $userInfos->timeout; + if ($timeout==0) { + $timeout = 1800; + } + + //Infos utilisateur + $this->User = new stdClass(); + $this->User->login = $userInfos->login; + $this->User->id = $userInfos->id; + $this->User->civilite = $userInfos->civilite; + $this->User->nom = $userInfos->nom; + $this->User->prenom = $userInfos->prenom; + $this->User->tel = $userInfos->tel; + $this->User->fax = $userInfos->fax; + $this->User->mobile = $userInfos->mobile; + $this->User->email = $userInfos->email; + $this->User->typeCompte = $userInfos->typeCompte; + $this->User->idClient = $userInfos->idClient; + $this->User->serviceCode = $userInfos->serviceCode; + $this->User->filtre_ip = $userInfos->filtre_ip; + $this->User->ipConnexion = $ip; + $this->User->pref = $userInfos->pref; + $this->User->rechRefType = $userInfos->rechRefType; + $this->User->profil = $userInfos->profil; + $this->User->nombreConnexions = $userInfos->nombreConnexions; + $this->User->dateDerniereConnexion = $userInfos->dateDerniereConnexion; + // Droits + $this->User->droits = array(); + $droits = explode(" ", $userInfos->droits); + if (count($droits) > 0) { + foreach ($droits as $droits) { + $this->User->droits[] = $droits; + } + } else { + //Inclure les droits du service ? + } + $this->User->droitsClients = $userInfos->droitsClients; + $this->User->timeout = $timeout; + $this->User->clientTest = $userInfos->clientTest; + $this->User->typeScore = $userInfos->typeScore; + $this->User->nbReponses = $userInfos->nbReponses; + $this->User->lang = $userInfos->lang; + $this->User->formatMail = $userInfos->formatMail; + $this->User->referenceParDefaut = $userInfos->referenceParDefaut; + $this->User->dateDebutCompte = $userInfos->dateDebutCompte; + $this->User->dateFinCompte = $userInfos->dateFinCompte; + $this->User->acceptationCGU = $userInfos->acceptationCGU; + $this->User->version = $userInfos->version; + + return true; + } + + return false; + } + + /** + * Authentification v2 + * @param object $userInfos + * @param string $credential + * @param string $ip + * @return string|boolean + */ + protected function authV2($userInfos, $credential, $ip) + { + $result = null; + try { + $sql = "SELECT * FROM sdv1.clients_services + WHERE IdClient = :client AND Code = :service"; + $stmt = $this->conn->prepare($sql); + $stmt->bindValue('client', $userInfos->idClient); + $stmt->bindValue('service', $userInfos->serviceCode); + $stmt->execute(); + if ($stmt->rowCount() > 0) { + $result = $stmt->fetch(\PDO::FETCH_OBJ); + } + } catch (\Doctrine\DBAL\DBALException $e) { + } + + // Aucun service + if ($result === null) { + return '0906'; + } + + // Service inactif + if ($result->Active == 0) { + return '0906'; + } + + // Block WebService User on Apps + if ($result->AppWebservice == 1 && $this->authApp !== null && $userInfos->idClient != 1) { + return '0901'; + } + + // WebService customize version + if ($result->AppWebservice == 1) { + // For customized version, check user is in the good service + $clients = include APPLICATION_PATH . '/../library/WsScore/Clients/ClientsConfig.php'; + foreach ($clients as $section => $params) { + if ($params['actif']) { + $wsClients[$params['idClient']] = $section; + } + } + if (array_key_exists($userInfos->idClient, $wsClients) + && ($this->serviceClient == false + || strtolower($this->serviceClientName) != $wsClients[$userInfos->idClient])) { + return '0901'; + } + } + + // Infos utilisateur + $this->User = new stdClass(); + $this->User->login = $userInfos->login; + $this->User->id = $userInfos->id; + $this->User->civilite = $userInfos->civilite; + $this->User->nom = $userInfos->nom; + $this->User->prenom = $userInfos->prenom; + $this->User->tel = $userInfos->tel; + $this->User->fax = $userInfos->fax; + $this->User->mobile = $userInfos->mobile; + $this->User->email = $userInfos->email; + $this->User->typeCompte = $userInfos->typeCompte; + $this->User->idClient = $userInfos->idClient; + $this->User->serviceCode = $userInfos->serviceCode; + $this->User->ipConnexion = $ip; + $this->User->pref = $userInfos->pref; + $this->User->rechRefType = $userInfos->rechRefType; + $this->User->profil = $userInfos->profil; + // Droits + $this->User->droits = array(); + $droits = explode(" ", $userInfos->droits); + if (count($droits) > 0) { + foreach ($droits as $droits) { + $this->User->droits[] = $droits; + } + } + $this->User->clientTest = $userInfos->clientTest; + $this->User->typeScore = $userInfos->typeScore; + $this->User->nbReponses = $userInfos->nbReponses; + $this->User->lang = $userInfos->lang; + $this->User->formatMail = $userInfos->formatMail; + $this->User->referenceParDefaut = $userInfos->referenceParDefaut; + $this->User->dateDebutCompte = $userInfos->dateDebutCompte; + $this->User->dateFinCompte = $userInfos->dateFinCompte; + $this->User->acceptationCGU = $userInfos->acceptationCGU; + $this->User->version = $userInfos->version; + + // Add Service Parameter to user definition + $this->User->typeScore = $result->TypeScore; + $this->User->timeout = $result->Timeout; + + /** + * Type de connexion + * userPassword => Vérifier le mot de passe + * userPasswordCrypt => Vérifier le mot de passe crypté + * userIP => Vérifier uniquement l'utilisateur et son IP de connexion + */ + switch ($result->TypeAcces) { + case 'userPassword': + if ($this->authIP($ip) === false) { + return '0904'; + } + if ($this->authPassword($userInfos, $credential) === true) { + if (count($this->User->droits) > 0) { + $this->User->droits = $this->getAccessList( + $userInfos->idClient, + $userInfos->serviceCode + ); + } + return true; + } + break; + case 'userPasswordCrypt': + if ($this->authIP($ip) === false) { + return '0904'; + } + if ($this->authPasswordCrypt($userInfos, $credential) === true) { + if (count($this->User->droits) > 0) { + $this->User->droits = $this->getAccessList( + $userInfos->idClient, + $userInfos->serviceCode + ); + } + return true; + } + break; + case 'userIP': + if (substr($credential, 0, 7) == 'iponly:') { + $ip = substr($credential, 7); + if ($this->authIP($ip) === true) { + if (count($this->User->droits) > 0) { + $this->User->droits = $this->getAccessList( + $userInfos->idClient, + $userInfos->serviceCode + ); + } + return true; + } + } + break; + } + + return false; + } + + /** + * Check password + * @todo : + * Check how password is check + * md5 => standard method md5 ( login | password ) + * key => get associated key with crypt method + * cert => get associated certificat + * @param unknown $userInfos + * @param unknown $password + * @return boolean + */ + protected function authPassword($userInfos, $password) + { + if (md5($userInfos->login.'|'.$userInfos->password) == $password) { + return true; + } + + if (md5($userInfos->password) == $password) { + return true; + } + + if ($userInfos->password == $password) { + return true; + } + + return false; + } + + /** + * Check password + * @param object $userInfos + * @param string $password + */ + protected function authPasswordCrypt($userInfos, $password) + { + if (substr($password, 0, 4) == '$2y$' + && strlen($password) == 60 + && $password == $userInfos->password) { + return true; + } + + if (password_verify($password, $userInfos->password) === true) { + return true; + } + + return false; + } + + /** + * Check ip + * @param string $ip + * @return string + */ + protected function authIP($ip) + { + //Check IP + if (!in_array($ip, $this->listApplicationIp)) { + try { + $sql = "SELECT IP FROM sdv1.clients_services_ip + WHERE IdClient = :client AND Service = :service"; + $stmt = $this->conn->prepare($sql); + $stmt->bindValue('client', $this->User->idClient); + $stmt->bindValue('service', $this->User->serviceCode); + $stmt->execute(); + if ($stmt->rowCount() > 0) { + $ipResult = $stmt->fetchAll(\PDO::FETCH_OBJ); + //Validation + $overallIpValidate = false; + foreach ($ipResult->IP as $filtre) { + if (trim($filtre) != '') { + // Is it a range ? + if (strpos($filtre, '-')) { + $validateIp = new Scores_Validate_IpInNetwork(); + $validateIp->setNetworkNotation($filtre); + $overallIpValidate = $validateIp->isValid($ip); + } + // Ip only + else { + if ($filtre === $ip) { + $overallIpValidate = true; + } + } + // Break foreach + if ($overallIpValidate === true) { + break; + } + } + } + // Exit with error + if ($overallIpValidate === false) { + return '0904'; + } + } + } catch (\Doctrine\DBAL\DBALException $e) { + } + } + } + + /** + * Log les erreurs d'authentification + * @param mixed $result + * @param string $ip + * @return void + */ + protected function authLog($login, $result, $ip) + { + $authenticate = null; + if ($result === false) { + $authenticate = 'KO'; + } elseif (is_string($result)) { + $authenticate = $result; + } + if ($authenticate !== null) { + $data = array( + 'login' => $login, + 'authenticate' => $authenticate, + 'ip' => $ip, + 'dateInsert' => date('YmdHis'), + ); + try { + $this->conn->insert('sdv1.utilisateurs_auth_log', $data); + } catch (\Doctrine\DBAL\DBALException $e) { + } + } + } + + /** + * Get Service Access List + * @param int $clientId + * @param string $serviceCode + * @return array + */ + protected function getAccessList($clientId, $serviceCode) + { + $list = array(); + try { + $sql = "SELECT Acces FROM sdv1.clients_services_droits + WHERE IdClient = :client AND Service = :service"; + $stmt = $this->conn->prepare($sql); + $stmt->bindValue('client', $this->User->idClient); + $stmt->bindValue('service', $this->User->serviceCode); + $stmt->execute(); + if ($stmt->rowCount() > 0) { + $accesResult = $stmt->fetchAll(\PDO::FETCH_OBJ); + foreach ($accesResult as $row) { + $list[] = $row->Acces; + } + } + } catch (\Doctrine\DBAL\DBALException $e) { + } + + return $list; + } + + protected function trigger($event, $args) + { + //Est ce que l'utilisateur à un trigger + + //Pour chaque trigger - Executer l'action + } +} diff --git a/src/Scores/Ws/Trigger.php b/src/Scores/Ws/Trigger.php new file mode 100644 index 0000000..0819586 --- /dev/null +++ b/src/Scores/Ws/Trigger.php @@ -0,0 +1,131 @@ +event = $event; + $this->userInfos = $userInfos; + $this->conn = Zend_Registry::get('doctrine'); + } + + /** + * Check if we have a trigger to execute + * @return number + */ + protected function hasTrigger() + { + if ($this->userInfos['Service'] === null) { + $service = 'default'; + } + + $sql = "SELECT * FROM sdv1.clients_services_trigger + WHERE idClient=:client AND service=:service AND (login=:login OR login='')"; + $stmtNb = 0; + try { + $stmt = $this->conn->prepare($sql); + $stmt->execute(); + $stmtNb = $stmt->rowCount(); + } catch (\Doctrine\DBAL\DBALException $e) { + if ($this->logger !== null) { + $this->logger->error($e->getMessage()); + } + } + if ($stmtNb > 0) { + while ($item = $stmt->fetch(PDO::FETCH_OBJ)) { + $tmp->action = $item->action; + $tmp->params = json_decode($item->actionParams, true); + $this->events[] = $tmp; + } + } + + return $stmtNb; + } + + /** + * Execute all triggers after hasTrigger + * @param array $args + * @return boolean + */ + protected function executeAllTrigger($args) + { + if (count($this->events)>0) { + foreach ($this->events as $action) { + $args = array_merge($args, $action->params); + switch ($action->action) { + case 'surveillance': + return $this->surveillance($args); + break; + } + } + } + } + + /** + * Mise en surveillance automatique + * @param array $args + * source, siren, ... + * @return boolean + */ + protected function surveillance($args) + { + if (!array_key_exists('source', $args)) { + return false; + } + + if (!array_key_exists('siren', $args)) { + return false; + } + + if (!array_key_exists('nic', $args)) { + return false; + } + + if (empty(trim($this->userInfos['email']))) { + return false; + } + + if (array_key_exists('ref', $args)) { + $ref = $args['ref']; + } + + try { + $this->conn->insert('jo.surveillances_site', array( + 'source' => $args['source'], + 'login' => $this->userInfos['login'], + 'email' => $this->userInfos['email'], + 'siren' => $args['siren'], + 'nic' => $args['nic'], + 'ref' => $ref, + 'encoursClient' => 0, + 'rs' => $args['Nom'], + 'cp' => $args['CP'], + 'ville' => $args['Ville'], + 'dateAjout' => date('Y-m-d'), + 'dateSuppr' => 0, + )); + return true; + } catch (\Doctrine\DBAL\DBALException $e) { + if ($this->logger !== null) { + $this->logger->error($e->getMessage()); + } + } + + return false; + } +}