Merge pull request #85 from gamonoid/dev

RC v20.3.0
This commit is contained in:
Thilina Hasantha
2017-11-26 21:45:16 +01:00
committed by GitHub
465 changed files with 51521 additions and 425 deletions

44
admin/data/LICENSE.txt Normal file
View File

@@ -0,0 +1,44 @@
ICEHRM END USER LICENSE AGREEMENT
NOTICE TO ALL USERS: BY PURCHASING THE MODULE, YOU (EITHER AN INDIVIDUAL OR A SINGLE ENTITY) CONSENT TO BE BOUND BY AND BECOME A PARTY TO THIS AGREEMENT.
All references to "Software" herein shall be deemed to include the software license with which you will be provided by Gamonoid Media Pvt Ltd, as part of the Software.
1. LICENSE GRANT. Subject to the payment of the applicable licence fees, and subject to the terms and conditions of this Agreement, ICEHRM hereby grants to you a non-exclusive, non-transferable right to use one copy of the specified version of the Software and the accompanying documentation (the "Documentation") for the term of this Agreement solely for your own internal business purposes. You may install one copy of the Software for production use.
.
2. USE. The Software is licensed as a single product; it may not be used on more than one ICEHRM Server at a time. The Software is "in use" on a Server when its installed on a Server. You shall not, nor permit any third party to copy (other than as expressly permitted herein). You shall not rent, lease or lend the Software to any other person, nor transfer or sub-licence your licence rights to any other person.
3. TERM. This Agreement is effective until terminated as set forth herein. This Agreement will terminate automatically if you fail to comply with any of the conditions, limitations or other requirements described herein. Upon any termination of this Agreement, you must immediately destroy all copies of the Software and the Documentation. You may terminate this Agreement at any point by destroying all copies of the Software and the Documentation.
4. SUPPORT. Gamonoid Media Pvt Ltd will provide you support according to the support agreement subscribed by the company.
5. OWNERSHIP RIGHTS. The Software is protected by copyright laws. ICEHRM and Gamonoid Media Pvt Ltd own and retain all right, title and interest in and to the Software, including all copyrights, patents, trademarks and other intellectual property rights therein. Your possession, installation, or use of the Software does not transfer to you any title to the intellectual property in the Software, and you will not acquire any rights to the Software except as expressly set forth in this Agreement.
6. LIMITED WARRANTY. You may not rent, lease, loan or resell the Software. You may not permit third parties to benefit from the use or functionality of the Software via a timesharing, service bureau or other arrangement, except to the extent such use is specified in the applicable list price or product packaging for the Software. You may not transfer any of the rights granted to you under this Agreement. You may not modify, or create derivative works based upon, the Software in whole or in part. You may not copy the Software or Documentation except as expressly permitted in Section 1 above. You may not remove any proprietary notices or labels on the Software. All rights not expressly set forth hereunder are reserved by ICEHRM. ICEHRM reserves the right to periodically conduct audits upon advance written notice to verify compliance with the terms of this Agreement.
7. WARRANTY and DISCLAIMER.
(i) Gamonoid Media Pvt Ltd. warrants that for 30 days from first download or installation the Software will perform substantially in accordance with the functionality described in the Documentation (http://blog.icehrm.com) when operated properly and in the manner specified in the Documentation.
(ii) You accept all responsibility for the selection of this Software to meet your requirements.
(iii) Gamonoid Media Pvt Ltd. does not warrant that the Software and/or the Documentation will be suitable for such requirements nor that any use will be uninterrupted and error free.
(iv) The warranty in (i) shall not apply if you (a) make or cause to be made any modifications to this Software, (b) use the Software in a manner for which it was not intended or (c) use the Software other than as permitted under this Agreement.
(vii) The warranties and conditions stated in this Agreement are in lieu of all other conditions, warranties or other terms concerning the supply or purported supply of, failure to supply or delay in supplying the Software or the Documentation which might but for this paragraph (vii) have effect between the ICEHRM and you or would otherwise be implied into or incorporated into this Agreement or any collateral contract, whether by statute, common law or otherwise, all of which are hereby excluded (including, without limitation, the implied conditions, warranties or other terms as to satisfactory quality, fitness for purpose or as to the use of reasonable skill and care).
8. LIMITATION of LIABILITY. Gamonoid Media Pvt Ltd. shall have no liability (whether in contract, tort, restitution or otherwise) for any of the following losses or damage (whether such losses or damage were foreseen, foreseeable, known or otherwise):
- Loss of revenue;
- Loss of actual or anticipated profits (including for loss of profits on contracts);
- Loss of the use of money;
- Loss of anticipated savings;
- Loss of business;
- Loss of opportunity;
- Loss of goodwill;
- Loss of reputation;
- Loss of, damage to or corruption of data;
or
Any indirect or consequential loss or damage howsoever caused (including, for the avoidance of doubt, where such loss or damage is of the type specified in paragraph (ii), (a) to (ii), (i).
The ICEHRM liability (whether in contract, tort, restitution or otherwise) arising out of or in connection with the supply of the Software shall in no circumstances exceed a sum equal to the amount equally paid by you for the Software.
The construction and interpretation of this Agreement shall be governed in accordance with the laws of Sri Lanka. The parties hereby submit to the jurisdiction of the courts of Sri Lanka save that ICEHRM as claimant shall be entitled to initiate proceedings in any court of competent jurisdiction.
This Agreement contains the entire understanding of the parties with respect to the subject matter hereof and supersedes all and any prior understandings, undertakings and promises between you and ICEHRM, whether oral or in writing, which have been given or may be implied from anything written or said in negotiations between us or our representatives prior to this Agreement and all prior agreements between the parties relating to the matters aforesaid shall cease to have effect as from the Effective Date.

7
admin/data/README.txt Normal file
View File

@@ -0,0 +1,7 @@
This module is licensed under IceHrm Commercial License, which can be found in LICENSE.txt.
You are allowed to make any modification required to these module, but only allowed to use
the module in one production server (even with modifications).
Installation
------------
Copy this module into <icehrm path>/admin/ directory

19
admin/data/index.php Normal file
View File

@@ -0,0 +1,19 @@
<?php
$moduleName = 'data';
define('MODULE_PATH',dirname(__FILE__));
include APP_BASE_PATH.'header.php';
include APP_BASE_PATH.'modulejslibs.inc.php';
$moduleBuilder = new \Classes\ModuleBuilder\ModuleBuilder();
$moduleBuilder->addModuleOrGroup(new \Classes\ModuleBuilder\ModuleTab(
'DataImport','DataImport','Data Importers','DataImportAdapter','','',true
));
$moduleBuilder->addModuleOrGroup(new \Classes\ModuleBuilder\ModuleTab(
'DataImportFile','DataImportFile','Data Import Files','DataImportFileAdapter','',''
));
echo \Classes\UIManager::getInstance()->renderModule($moduleBuilder);
include APP_BASE_PATH.'footer.php';

177
admin/data/lib.js Normal file
View File

@@ -0,0 +1,177 @@
/**
* Author: Thilina Hasantha
*/
/**
* DataImportAdapter
*/
function DataImportAdapter(endPoint,tab,filter,orderBy) {
this.initAdapter(endPoint,tab,filter,orderBy);
}
DataImportAdapter.inherits(AdapterBase);
DataImportAdapter.method('getDataMapping', function() {
return [
"id",
"name",
"dataType",
"details"
];
});
DataImportAdapter.method('getHeaders', function() {
return [
{ "sTitle": "ID" ,"bVisible":false},
{ "sTitle": "Name" },
{ "sTitle": "Data Type" },
{ "sTitle": "Details" }
];
});
DataImportAdapter.method('getFormFields', function() {
return [
[ "id", {"label":"ID","type":"hidden"}],
[ "name", {"label":"Name","type":"text","validation":""}],
[ "dataType", {"label":"Data Type","type":"text","validation":""}],
[ "details", {"label":"Details","type":"textarea","validation":"none"}],
[ "columns", {"label":"Columns","type":"datagroup",
"form":[
[ "name", {"label":"Name","type":"text","validation":""}],
[ "title", {"label":"Filed Title","type":"text","validation":"none"}],
[ "type", {"label":"Type","type":"select","sort": "none","source":[["Normal","Normal"],["Reference","Reference"],["Attached","Attached"]]}],
[ "dependOn", {"label":"Depends On","type":"select","allow-null":true,"null-label":"N/A","source":[["EmergencyContact","Emergency Contacts"],["Ethnicity","Ethnicity"],["Nationality","Nationality"],["JobTitle","JobTitle"],["PayFrequency","PayFrequency"],["PayGrade","PayGrade"],["EmploymentStatus","EmploymentStatus"],["CompanyStructure","CompanyStructure"],["Employee","Employee"]]}],
[ "dependOnField", {"label":"Depends On Field","type":"text","validation":"none"}],
[ "isKeyField", {"label":"Is Key Field","type":"select","validation":"","source":[["No","No"],["Yes","Yes"]]}],
[ "idField", {"label":"Is ID Field","type":"select","validation":"","source":[["No","No"],["Yes","Yes"]]}]
],
"html":'<div id="#_id_#" class="panel panel-default"><div class="panel-heading"><b>#_name_#</b> #_delete_##_edit_#</div><div class="panel-body"><b>Header Title: </b>#_title_#<br/><span style="color:#999;font-size:11px;font-weight:bold">Type: #_type_# </span><br/></div></div>',
"validation":"none",
"custom-validate-function":function (data){
var res = {};
res['params'] = data;
res['valid'] = true;
if(data.type == 'Reference'){
if(data.dependOn == "NULL"){
res['message'] = "If the type is Reference this field should referring another table";
res['valid'] = false;
}else if(dependOnField == null || dependOnField == undefined){
res['message'] = "If the type is Reference then 'Depends On Field' can not be empty";
res['valid'] = false;
}
}
return res;
}
}],
];
});
/**
* DataImportFileAdapter
*/
function DataImportFileAdapter(endPoint,tab,filter,orderBy) {
this.initAdapter(endPoint,tab,filter,orderBy);
}
DataImportFileAdapter.inherits(AdapterBase);
DataImportFileAdapter.method('getDataMapping', function() {
return [
"id",
"name",
"data_import_definition",
"status"
];
});
DataImportFileAdapter.method('getHeaders', function() {
return [
{ "sTitle": "ID" ,"bVisible":false},
{ "sTitle": "Name" },
{ "sTitle": "Data Import Definition" },
{ "sTitle": "Status" }
];
});
DataImportFileAdapter.method('getFormFields', function() {
return [
[ "id", {"label":"ID","type":"hidden"}],
[ "name", {"label":"Name","type":"text","validation":""}],
[ "data_import_definition", {"label":"Data Import Definitions","type":"select","remote-source":["DataImport","id","name"]}],
[ "file", {"label":"File to Import","type":"fileupload","validation":"","filetypes":"csv,txt"}],
[ "details", {"label":"Last Export Result","type":"textarea","validation":"none"}]
];
});
DataImportFileAdapter.method('getActionButtonsHtml', function(id,data) {
var editButton = '<img class="tableActionButton" src="_BASE_images/edit.png" style="cursor:pointer;" rel="tooltip" title="Edit" onclick="modJs.edit(_id_);return false;"></img>';
var processButton = '<img class="tableActionButton" src="_BASE_images/run.png" style="margin-left:15px;cursor:pointer;" rel="tooltip" title="Process" onclick="modJs.process(_id_,\'_status_\');return false;"></img>';
var deleteButton = '<img class="tableActionButton" src="_BASE_images/delete.png" style="margin-left:15px;cursor:pointer;" rel="tooltip" title="Delete" onclick="modJs.deleteRow(_id_);return false;"></img>';
var cloneButton = '<img class="tableActionButton" src="_BASE_images/clone.png" style="margin-left:15px;cursor:pointer;" rel="tooltip" title="Copy" onclick="modJs.copyRow(_id_);return false;"></img>';
var html = '<div style="width:120px;">_edit__process__clone__delete_</div>';
if(this.showAddNew){
html = html.replace('_clone_',cloneButton);
}else{
html = html.replace('_clone_','');
}
if(this.showDelete){
html = html.replace('_delete_',deleteButton);
}else{
html = html.replace('_delete_','');
}
if(this.showEdit){
html = html.replace('_edit_',editButton);
}else{
html = html.replace('_edit_','');
}
if (data[3] == 'Not Processed') {
html = html.replace('_process_',processButton);
} else {
html = html.replace('_process_','');
}
html = html.replace(/_id_/g,id);
html = html.replace(/_status_/g,data[6]);
html = html.replace(/_BASE_/g,this.baseUrl);
return html;
});
DataImportFileAdapter.method('process', function(id) {
var that = this;
var object = {"id":id};
var reqJson = JSON.stringify(object);
var callBackData = [];
callBackData['callBackData'] = [];
callBackData['callBackSuccess'] = 'processSuccessCallBack';
callBackData['callBackFail'] = 'processFailCallBack';
this.customAction('processDataFile','admin=data',reqJson,callBackData);
});
DataImportFileAdapter.method('processSuccessCallBack', function(callBackData) {
this.showMessage("Success", "File imported successfully.");
});
DataImportFileAdapter.method('processFailCallBack', function(callBackData) {
this.showMessage("Error", "File import unsuccessful. Result:"+callBackData);
});

12
admin/data/meta.json Normal file
View File

@@ -0,0 +1,12 @@
{
"label": "Data",
"menu": "System",
"order": "8",
"icon": "fa-database",
"user_levels": [
"Admin"
],
"permissions": [],
"model_namespace": "\\Data\\Common\\Model",
"manager": "\\Data\\Admin\\Api\\DataAdminManager"
}

View File

@@ -197,9 +197,9 @@ EmployeeAdapter.method('getFormFields', function() {
[ "department", {"label":"Department","type":"select2","remote-source":["CompanyStructure","id","title"]}], [ "department", {"label":"Department","type":"select2","remote-source":["CompanyStructure","id","title"]}],
[ "supervisor", {"label":"Direct Supervisor","type":"select2","allow-null":true,"remote-source":["Employee","id","first_name+last_name"]}], [ "supervisor", {"label":"Direct Supervisor","type":"select2","allow-null":true,"remote-source":["Employee","id","first_name+last_name"]}],
[ "indirect_supervisors", {"label":"Indirect Supervisors","type":"select2multi","allow-null":true,"remote-source":["Employee","id","first_name+last_name"]}], [ "indirect_supervisors", {"label":"Indirect Supervisors","type":"select2multi","allow-null":true,"remote-source":["Employee","id","first_name+last_name"]}],
[ "approver1", {"label":"First Level Approver","type":"select2","allow-null":true,"remote-source":["Employee","id","first_name+last_name"]}], [ "approver1", {"label":"First Level Approver","type":"select2","allow-null":true,"null-label":"None","remote-source":["Employee","id","first_name+last_name"]}],
[ "approver2", {"label":"Second Level Approver","type":"select2","allow-null":true,"remote-source":["Employee","id","first_name+last_name"]}], [ "approver2", {"label":"Second Level Approver","type":"select2","allow-null":true,"null-label":"None","remote-source":["Employee","id","first_name+last_name"]}],
[ "approver3", {"label":"Third Level Approver","type":"select2","allow-null":true,"remote-source":["Employee","id","first_name+last_name"]}], [ "approver3", {"label":"Third Level Approver","type":"select2","allow-null":true,"null-label":"None","remote-source":["Employee","id","first_name+last_name"]}],
[ "notes", {"label":"Notes","type":"datagroup", [ "notes", {"label":"Notes","type":"datagroup",
"form":[ "form":[
[ "note", {"label":"Note","type":"textarea","validation":""}] [ "note", {"label":"Note","type":"textarea","validation":""}]
@@ -252,7 +252,7 @@ EmployeeAdapter.method('getFilters', function() {
}); });
EmployeeAdapter.method('getActionButtonsHtml', function(id) { EmployeeAdapter.method('getActionButtonsHtml', function(id) {
var html = '<div style="width:110px;"><img class="tableActionButton" src="_BASE_images/user.png" style="cursor:pointer;" rel="tooltip" title="Login as this Employee" onclick="modJs.setAdminProfile(_id_);return false;"></img><img class="tableActionButton" src="_BASE_images/view.png" style="cursor:pointer;margin-left:15px;" rel="tooltip" title="View" onclick="modJs.view(_id_);return false;"></img><img class="tableActionButton" src="_BASE_images/edit.png" style="display:none;cursor:pointer;margin-left:15px;" rel="tooltip" title="Edit" onclick="modJs.edit(_id_);return false;"></img><img class="tableActionButton" src="_BASE_images/connect-no.png" style="margin-left:15px;cursor:pointer;" rel="tooltip" title="Terminate Employee" onclick="modJs.terminateEmployee(_id_);return false;"></img></div>'; var html = '<div style="width:110px;"><img class="tableActionButton" src="_BASE_images/user.png" style="cursor:pointer;" rel="tooltip" title="Login as this Employee" onclick="modJs.setAdminProfile(_id_);return false;"></img><img class="tableActionButton" src="_BASE_images/view.png" style="cursor:pointer;margin-left:15px;" rel="tooltip" title="View" onclick="modJs.view(_id_);return false;"></img><img class="tableActionButton" src="_BASE_images/edit.png" style="cursor:pointer;margin-left:15px;" rel="tooltip" title="Edit" onclick="modJs.edit(_id_);return false;"></img><img class="tableActionButton" src="_BASE_images/edit.png" style="display:none;cursor:pointer;margin-left:15px;" rel="tooltip" title="Edit" onclick="modJs.edit(_id_);return false;"></img><img class="tableActionButton" src="_BASE_images/connect-no.png" style="margin-left:15px;cursor:pointer;" rel="tooltip" title="Terminate Employee" onclick="modJs.terminateEmployee(_id_);return false;"></img></div>';
html = html.replace(/_id_/g,id); html = html.replace(/_id_/g,id);
html = html.replace(/_BASE_/g,this.baseUrl); html = html.replace(/_BASE_/g,this.baseUrl);
return html; return html;

View File

@@ -1,10 +1,10 @@
<?php <?php
/* /*
This file is part of Ice Framework. This file is part of Ice Framework.
------------------------------------------------------------------ ------------------------------------------------------------------
Original work Copyright (c) 2012 [Gamonoid Media Pvt. Ltd] Original work Copyright (c) 2012 [Gamonoid Media Pvt. Ltd]
Developer: Thilina Hasantha (thilina.hasantha[at]gmail.com / facebook.com/thilinah) Developer: Thilina Hasantha (thilina.hasantha[at]gmail.com / facebook.com/thilinah)
*/ */
@@ -13,12 +13,12 @@ define('MODULE_PATH',dirname(__FILE__));
include APP_BASE_PATH.'header.php'; include APP_BASE_PATH.'header.php';
include APP_BASE_PATH.'modulejslibs.inc.php'; include APP_BASE_PATH.'modulejslibs.inc.php';
?><div class="span9"> ?><div class="span9">
<ul class="nav nav-tabs" id="modTab" style="margin-bottom:0px;margin-left:5px;border-bottom: none;"> <ul class="nav nav-tabs" id="modTab" style="margin-bottom:0px;margin-left:5px;border-bottom: none;">
<li class="active"><a id="tabEmployeeFieldName" href="#tabPageEmployeeFieldName"><?=t('Employee Field Names')?></a></li> <li class="active"><a id="tabEmployeeFieldName" href="#tabPageEmployeeFieldName"><?=t('Employee Field Names')?></a></li>
<li><a id="tabEmployeeCustomField" href="#tabPageEmployeeCustomField"><?=t('Employee Custom Fields')?></a></li> <li><a id="tabEmployeeCustomField" href="#tabPageEmployeeCustomField"><?=t('Employee Custom Fields')?></a></li>
</ul> </ul>
<div class="tab-content"> <div class="tab-content">
<div class="tab-pane active" id="tabPageEmployeeFieldName"> <div class="tab-pane active" id="tabPageEmployeeFieldName">
<div id="EmployeeFieldName" class="reviewBlock" data-content="List" style="padding-left:5px;"> <div id="EmployeeFieldName" class="reviewBlock" data-content="List" style="padding-left:5px;">
@@ -44,6 +44,7 @@ var modJsList = new Array();
modJsList['tabEmployeeFieldName'] = new FieldNameAdapter('FieldNameMapping','EmployeeFieldName',{"type":"Employee"}); modJsList['tabEmployeeFieldName'] = new FieldNameAdapter('FieldNameMapping','EmployeeFieldName',{"type":"Employee"});
modJsList['tabEmployeeFieldName'].setRemoteTable(true); modJsList['tabEmployeeFieldName'].setRemoteTable(true);
modJsList['tabEmployeeFieldName'].setShowDelete(false);
modJsList['tabEmployeeFieldName'].setShowAddNew(false); modJsList['tabEmployeeFieldName'].setShowAddNew(false);
modJsList['tabEmployeeCustomField'] = new CustomFieldAdapter('CustomField','EmployeeCustomField',{"type":"Employee"},"display_order desc"); modJsList['tabEmployeeCustomField'] = new CustomFieldAdapter('CustomField','EmployeeCustomField',{"type":"Employee"},"display_order desc");
@@ -54,4 +55,4 @@ modJsList['tabEmployeeCustomField'].setTableType("Employee");
var modJs = modJsList['tabEmployeeFieldName']; var modJs = modJsList['tabEmployeeFieldName'];
</script> </script>
<?php include APP_BASE_PATH.'footer.php';?> <?php include APP_BASE_PATH.'footer.php';?>

View File

@@ -8,7 +8,7 @@
*/ */
function FieldNameAdapter(endPoint,tab,filter,orderBy) { function FieldNameAdapter(endPoint,tab,filter,orderBy) {
this.initAdapter(endPoint,tab,filter,orderBy); this.initAdapter(endPoint,tab,filter,orderBy);
} }
FieldNameAdapter.inherits(AdapterBase); FieldNameAdapter.inherits(AdapterBase);
@@ -17,32 +17,32 @@ FieldNameAdapter.inherits(AdapterBase);
FieldNameAdapter.method('getDataMapping', function() { FieldNameAdapter.method('getDataMapping', function() {
return [ return [
"id", "id",
"name", "name",
"textOrig", "textOrig",
"textMapped", "textMapped",
"display" "display"
]; ];
}); });
FieldNameAdapter.method('getHeaders', function() { FieldNameAdapter.method('getHeaders', function() {
return [ return [
{ "sTitle": "ID" ,"bVisible":false}, { "sTitle": "ID" ,"bVisible":false},
{ "sTitle": "Name" }, { "sTitle": "Name" },
{ "sTitle": "Original Text"}, { "sTitle": "Original Text"},
{ "sTitle": "Mapped Text"}, { "sTitle": "Mapped Text"},
{ "sTitle": "Display Status"} { "sTitle": "Display Status"}
]; ];
}); });
FieldNameAdapter.method('getFormFields', function() { FieldNameAdapter.method('getFormFields', function() {
return [ return [
[ "id", {"label":"ID","type":"hidden"}], [ "id", {"label":"ID","type":"hidden"}],
[ "type", {"label":"Type","type":"placeholder","validation":""}], [ "type", {"label":"Type","type":"placeholder","validation":""}],
[ "name", {"label":"Name","type":"placeholder","validation":""}], [ "name", {"label":"Name","type":"placeholder","validation":""}],
[ "textOrig", {"label":"Original Text","type":"placeholder","validation":""}], [ "textOrig", {"label":"Original Text","type":"placeholder","validation":""}],
[ "textMapped", {"label":"Mapped Text","type":"text","validation":""}], [ "textMapped", {"label":"Mapped Text","type":"text","validation":""}],
[ "display", {"label":"Display Status","type":"select","source":[["Form","Form"],["Table and Form","Table and Form"],["Hidden","Hidden"]]}] [ "display", {"label":"Display Status","type":"select","source":[["Form","Show"],["Hidden","Hidden"]]}]
]; ];
}); });
@@ -51,7 +51,7 @@ FieldNameAdapter.method('getFormFields', function() {
*/ */
function CustomFieldAdapter(endPoint,tab,filter,orderBy) { function CustomFieldAdapter(endPoint,tab,filter,orderBy) {
this.initAdapter(endPoint,tab,filter,orderBy); this.initAdapter(endPoint,tab,filter,orderBy);
this.tableType = ""; this.tableType = "";
} }
@@ -61,41 +61,41 @@ CustomFieldAdapter.inherits(AdapterBase);
CustomFieldAdapter.method('getDataMapping', function() { CustomFieldAdapter.method('getDataMapping', function() {
return [ return [
"id", "id",
"name", "name",
"display", "display",
"display_order" "display_order"
]; ];
}); });
CustomFieldAdapter.method('getHeaders', function() { CustomFieldAdapter.method('getHeaders', function() {
return [ return [
{ "sTitle": "ID" ,"bVisible":false}, { "sTitle": "ID" ,"bVisible":false},
{ "sTitle": "Name" }, { "sTitle": "Name" },
{ "sTitle": "Display Status"}, { "sTitle": "Display Status"},
{ "sTitle": "Priority"} { "sTitle": "Priority"}
]; ];
}); });
CustomFieldAdapter.method('getFormFields', function() { CustomFieldAdapter.method('getFormFields', function() {
return [ return [
[ "id", {"label":"ID","type":"hidden"}], [ "id", {"label":"ID","type":"hidden"}],
//[ "type", {"label":"Type","type":"placeholder","validation":""}], //[ "type", {"label":"Type","type":"placeholder","validation":""}],
[ "name", {"label":"Name","type":"text","validation":""}], [ "name", {"label":"Name","type":"text","validation":""}],
[ "display", {"label":"Display Status","type":"select","source":[["Form","Show"],["Hidden","Hidden"]]}], [ "display", {"label":"Display Status","type":"select","source":[["Form","Show"],["Hidden","Hidden"]]}],
[ "field_type", {"label":"Field Type","type":"select","source":[["text","Text Field"],["textarea","Text Area"],["select","Select"],["select2","Select2"],["select2multi","Multi Select"],["fileupload","File Upload"],["date","Date"],["datetime","Date Time"],["time","Time"]]}], [ "field_type", {"label":"Field Type","type":"select","source":[["text","Text Field"],["textarea","Text Area"],["select","Select"],["select2","Select2"],["select2multi","Multi Select"],["fileupload","File Upload"],["date","Date"],["datetime","Date Time"],["time","Time"]]}],
[ "field_label", {"label":"Field Label","type":"text","validation":""}], [ "field_label", {"label":"Field Label","type":"text","validation":""}],
[ "field_validation", {"label":"Validation","type":"select","validation":"none","sort":"none","source":[["","Required"],["none","None"],["number","Number"],["numberOrEmpty","Number or Empty"],["float","Decimal"],["email","Email"],["emailOrEmpty","Email or Empty"]]}], [ "field_validation", {"label":"Validation","type":"select","validation":"none","sort":"none","source":[["","Required"],["none","None"],["number","Number"],["numberOrEmpty","Number or Empty"],["float","Decimal"],["email","Email"],["emailOrEmpty","Email or Empty"]]}],
[ "field_options", {"label":"Field Options","type":"datagroup", [ "field_options", {"label":"Field Options","type":"datagroup",
"form":[ "form":[
[ "label", {"label":"Label","type":"text","validation":""}], [ "label", {"label":"Label","type":"text","validation":""}],
[ "value", {"label":"Value","type":"text","validation":"none"}] [ "value", {"label":"Value","type":"text","validation":"none"}]
], ],
"html":'<div id="#_id_#" class="panel panel-default"><div class="panel-body">#_delete_##_edit_#<span style="color:#999;font-size:13px;font-weight:bold">#_label_#</span>:#_value_#</div></div>', "html":'<div id="#_id_#" class="panel panel-default"><div class="panel-body">#_delete_##_edit_#<span style="color:#999;font-size:13px;font-weight:bold">#_label_#</span>:#_value_#</div></div>',
"validation":"none" "validation":"none"
}], }],
[ "display_order", {"label":"Priority","type":"text","validation":"number"}], [ "display_order", {"label":"Priority","type":"text","validation":"number"}],
[ "display_section", {"label":"Display Section","type":"text","validation":""}] [ "display_section", {"label":"Display Section","type":"text","validation":""}]
]; ];
}); });

View File

@@ -109,7 +109,7 @@ include APP_BASE_PATH.'modulejslibs.inc.php';
modJsList['tabPayrollData'].setColumnFieldName('payroll_item'); modJsList['tabPayrollData'].setColumnFieldName('payroll_item');
modJsList['tabPayrollData'].setTables('PayrollEmployee','PayrollColumn','PayrollData'); modJsList['tabPayrollData'].setTables('PayrollEmployee','PayrollColumn','PayrollData');
modJsList['tabPayrollColumn'] = new PayrollColumnAdapter('PayrollColumn','PayrollColumn','','name, colorder'); modJsList['tabPayrollColumn'] = new PayrollColumnAdapter('PayrollColumn','PayrollColumn','','deduction_group, colorder');
modJsList['tabPayrollColumn'].setRemoteTable(true); modJsList['tabPayrollColumn'].setRemoteTable(true);
//modJsList['tabPayrollColumnTemplate'] = new PayrollColumnTemplateAdapter('PayrollColumnTemplate','PayrollColumnTemplate'); //modJsList['tabPayrollColumnTemplate'] = new PayrollColumnTemplateAdapter('PayrollColumnTemplate','PayrollColumnTemplate');

View File

@@ -297,6 +297,7 @@ PayrollColumnAdapter.method('getDataMapping', function() {
"name", "name",
"colorder", "colorder",
"calculation_hook", "calculation_hook",
"deduction_group",
"editable", "editable",
"enabled" "enabled"
]; ];
@@ -308,6 +309,7 @@ PayrollColumnAdapter.method('getHeaders', function() {
{ "sTitle": "Name"}, { "sTitle": "Name"},
{ "sTitle": "Column Order"}, { "sTitle": "Column Order"},
{ "sTitle": "Calculation Method"}, { "sTitle": "Calculation Method"},
{ "sTitle": "Calculation Group"},
{ "sTitle": "Editable"}, { "sTitle": "Editable"},
{ "sTitle": "Enabled"} { "sTitle": "Enabled"}
]; ];
@@ -334,6 +336,7 @@ PayrollColumnAdapter.method('getFormFields', function() {
[ "id", {"label":"ID","type":"hidden"}], [ "id", {"label":"ID","type":"hidden"}],
[ "name", {"label":"Name","type":"text","validation":""}], [ "name", {"label":"Name","type":"text","validation":""}],
[ "calculation_hook", {"label":"Predefined Calculations","type":"select2","allow-null":true,"null-label":"None","remote-source":["CalculationHook","code","name"]}], [ "calculation_hook", {"label":"Predefined Calculations","type":"select2","allow-null":true,"null-label":"None","remote-source":["CalculationHook","code","name"]}],
[ "deduction_group", {"label":"Calculation Group","type":"select2","allow-null":true,"null-label":"Common","remote-source":["DeductionGroup","id","name"]}],
[ "salary_components", {"label":"Salary Components","type":"select2multi","remote-source":["SalaryComponent","id","name"]}], [ "salary_components", {"label":"Salary Components","type":"select2multi","remote-source":["SalaryComponent","id","name"]}],
[ "deductions", {"label":"Calculation Method","type":"select2multi","remote-source":["Deduction","id","name"]}], [ "deductions", {"label":"Calculation Method","type":"select2multi","remote-source":["Deduction","id","name"]}],
[ "add_columns", {"label":"Columns to Add","type":"select2multi","remote-source":["PayrollColumn","id","name"]}], [ "add_columns", {"label":"Columns to Add","type":"select2multi","remote-source":["PayrollColumn","id","name"]}],
@@ -347,6 +350,12 @@ PayrollColumnAdapter.method('getFormFields', function() {
]; ];
}); });
PayrollColumnAdapter.method('getFilters', function() {
return [
[ "deduction_group", {"label":"Calculation Group","type":"select2","allow-null":true,"null-label":"Any","remote-source":["DeductionGroup","id","name"]}]
];
});

View File

@@ -1,38 +1,48 @@
<?php <?php
$moduleName = 'Reports'; $moduleName = 'Reports';
define('MODULE_PATH',dirname(__FILE__)); define('MODULE_PATH',dirname(__FILE__));
include APP_BASE_PATH.'header.php'; include APP_BASE_PATH.'header.php';
include APP_BASE_PATH.'modulejslibs.inc.php'; include APP_BASE_PATH.'modulejslibs.inc.php';
?><div class="span9"> ?><div class="span9">
<ul class="nav nav-tabs" id="modTab" style="margin-bottom:0px;margin-left:5px;border-bottom: none;"> <ul class="nav nav-tabs" id="modTab" style="margin-bottom:0px;margin-left:5px;border-bottom: none;">
<li class="active"><a id="tabReport" href="#tabPageReport"><?=t('Reports')?></a></li> <li class="active"><a id="tabReport" href="#tabPageReport"><?=t('Reports')?></a></li>
<li class=""><a id="tabExports" href="#tabPageExports"><?=t('Exports')?></a></li>
</ul> </ul>
<div class="tab-content"> <div class="tab-content">
<div class="tab-pane active" id="tabPageReport"> <div class="tab-pane active" id="tabPageReport">
<div id="Report" class="reviewBlock" data-content="List" style="padding-left:5px;"> <div id="Report" class="reviewBlock" data-content="List" style="padding-left:5px;">
</div> </div>
<div id="ReportForm" class="reviewBlock" data-content="Form" style="padding-left:5px;display:none;"> <div id="ReportForm" class="reviewBlock" data-content="Form" style="padding-left:5px;display:none;">
</div> </div>
</div> </div>
<div class="tab-pane" id="tabPageExports">
<div id="Exports" class="reviewBlock" data-content="List" style="padding-left:5px;">
</div>
<div id="ExportsForm" class="reviewBlock" data-content="Form" style="padding-left:5px;display:none;">
</div>
</div>
</div> </div>
</div> </div>
<script> <script>
var modJsList = new Array(); var modJsList = new Array();
modJsList['tabReport'] = new ReportAdapter('Report','Report','','report_group'); modJsList['tabReport'] = new ReportAdapter('Report','Report','{"type":"Reports"}','report_group');
modJsList['tabReport'].setShowAddNew(false); modJsList['tabReport'].setShowAddNew(false);
modJsList['tabReport'].setRemoteTable(true); modJsList['tabReport'].setRemoteTable(true);
modJsList['tabExports'] = new ReportAdapter('Report','Exports','{"type":"Exports"}','report_group');
modJsList['tabExports'].setShowAddNew(false);
modJsList['tabExports'].setRemoteTable(true);
var modJs = modJsList['tabReport']; var modJs = modJsList['tabReport'];
</script> </script>
<?php include APP_BASE_PATH.'footer.php';?> <?php include APP_BASE_PATH.'footer.php';?>

View File

@@ -78,17 +78,17 @@ ReportAdapter.method('processFormFieldsWithObject', function(object) {
that.remoteFieldsExists = true; that.remoteFieldsExists = true;
} }
}); });
} }
} }
var tempArray = []; var tempArray = [];
that._formFileds.forEach(function(entry) { that._formFileds.forEach(function(entry) {
if(jQuery.inArray(entry[0], fieldsToDelete) < 0){ if(jQuery.inArray(entry[0], fieldsToDelete) < 0){
tempArray.push(entry); tempArray.push(entry);
} }
}); });
that._formFileds = tempArray; that._formFileds = tempArray;
}); });
@@ -107,7 +107,7 @@ ReportAdapter.method('renderForm', function(object) {
} }
this.currentReport = object; this.currentReport = object;
}); });
ReportAdapter.method('renderFormNew', function(object) { ReportAdapter.method('renderFormNew', function(object) {
@@ -284,8 +284,8 @@ ReportAdapter.method('addSuccessCallBack', function(callBackData,serverData) {
link = '<a href="'+modJs.getCustomActionUrl("download",{'file':fileName})+'" target="_blank" style="font-size:14px;font-weight:bold;">Download Report <img src="_BASE_images/download.png"></img> </a>'; link = '<a href="'+modJs.getCustomActionUrl("download",{'file':fileName})+'" target="_blank" style="font-size:14px;font-weight:bold;">Download Report <img src="_BASE_images/download.png"></img> </a>';
} }
link = link.replace(/_BASE_/g,this.baseUrl); link = link.replace(/_BASE_/g,this.baseUrl);
if(this.currentReport.output == "PDF"){ if(this.currentReport.output == "PDF" || this.currentReport.output == "JSON"){
this.showMessage("Download Report",link); this.showMessage("Download Report",link);
@@ -352,7 +352,7 @@ ReportAdapter.method('fillForm', function(object) {
}else{ }else{
$("#"+this.getTableName()+'Form #'+fields[i][0]).val(object[fields[i][0]]); $("#"+this.getTableName()+'Form #'+fields[i][0]).val(object[fields[i][0]]);
} }
} }
}); });

View File

@@ -55,7 +55,12 @@ UserAdapter.method('changePassword', function() {
}); });
UserAdapter.method('saveUserSuccessCallBack', function(callBackData,serverData) { UserAdapter.method('saveUserSuccessCallBack', function(callBackData,serverData) {
this.showMessage("Create User","An email has been sent to "+callBackData['email']+" with a temporary password to login to IceHrm."); var user = callBackData[0];
if (callBackData[1]) {
this.showMessage("Create User","An email has been sent to "+user['email']+" with a temporary password to login to IceHrm.");
} else {
this.showMessage("Create User","User created successfully. But there was a problem sending welcome email.");
}
this.get([]); this.get([]);
}); });
@@ -76,7 +81,7 @@ UserAdapter.method('save', function() {
var validator = new FormValidation(this.getTableName()+"_submit",true,{'ShowPopup':false,"LabelErrorClass":"error"}); var validator = new FormValidation(this.getTableName()+"_submit",true,{'ShowPopup':false,"LabelErrorClass":"error"});
if(validator.checkValues()){ if(validator.checkValues()){
var params = validator.getFormParameters(); var params = validator.getFormParameters();
var msg = this.doCustomValidation(params); var msg = this.doCustomValidation(params);
if(msg == null){ if(msg == null){
var id = $('#'+this.getTableName()+"_submit #id").val(); var id = $('#'+this.getTableName()+"_submit #id").val();
@@ -84,63 +89,63 @@ UserAdapter.method('save', function() {
$(params).attr('id',id); $(params).attr('id',id);
this.add(params,[]); this.add(params,[]);
}else{ }else{
var reqJson = JSON.stringify(params); var reqJson = JSON.stringify(params);
var callBackData = []; var callBackData = [];
callBackData['callBackData'] = []; callBackData['callBackData'] = [];
callBackData['callBackSuccess'] = 'saveUserSuccessCallBack'; callBackData['callBackSuccess'] = 'saveUserSuccessCallBack';
callBackData['callBackFail'] = 'saveUserFailCallBack'; callBackData['callBackFail'] = 'saveUserFailCallBack';
this.customAction('saveUser','admin=users',reqJson,callBackData); this.customAction('saveUser','admin=users',reqJson,callBackData);
} }
}else{ }else{
//$("#"+this.getTableName()+'Form .label').html(msg); //$("#"+this.getTableName()+'Form .label').html(msg);
//$("#"+this.getTableName()+'Form .label').show(); //$("#"+this.getTableName()+'Form .label').show();
this.showMessage("Error Saving User",msg); this.showMessage("Error Saving User",msg);
} }
} }
}); });
UserAdapter.method('changePasswordConfirm', function() { UserAdapter.method('changePasswordConfirm', function() {
$('#adminUsersChangePwd_error').hide(); $('#adminUsersChangePwd_error').hide();
var passwordValidation = function (str) { var passwordValidation = function (str) {
var val = /^[a-zA-Z0-9]\w{6,}$/; var val = /^[a-zA-Z0-9]\w{6,}$/;
return str != null && val.test(str); return str != null && val.test(str);
}; };
var password = $('#adminUsersChangePwd #newpwd').val(); var password = $('#adminUsersChangePwd #newpwd').val();
if(!passwordValidation(password)){ if(!passwordValidation(password)){
$('#adminUsersChangePwd_error').html("Password may contain only letters, numbers and should be longer than 6 characters"); $('#adminUsersChangePwd_error').html("Password may contain only letters, numbers and should be longer than 6 characters");
$('#adminUsersChangePwd_error').show(); $('#adminUsersChangePwd_error').show();
return; return;
} }
var conPassword = $('#adminUsersChangePwd #conpwd').val(); var conPassword = $('#adminUsersChangePwd #conpwd').val();
if(conPassword != password){ if(conPassword != password){
$('#adminUsersChangePwd_error').html("Passwords don't match"); $('#adminUsersChangePwd_error').html("Passwords don't match");
$('#adminUsersChangePwd_error').show(); $('#adminUsersChangePwd_error').show();
return; return;
} }
var req = {"id":this.currentId,"pwd":conPassword}; var req = {"id":this.currentId,"pwd":conPassword};
var reqJson = JSON.stringify(req); var reqJson = JSON.stringify(req);
var callBackData = []; var callBackData = [];
callBackData['callBackData'] = []; callBackData['callBackData'] = [];
callBackData['callBackSuccess'] = 'changePasswordSuccessCallBack'; callBackData['callBackSuccess'] = 'changePasswordSuccessCallBack';
callBackData['callBackFail'] = 'changePasswordFailCallBack'; callBackData['callBackFail'] = 'changePasswordFailCallBack';
this.customAction('changePassword','admin=users',reqJson,callBackData); this.customAction('changePassword','admin=users',reqJson,callBackData);
}); });
UserAdapter.method('closeChangePassword', function() { UserAdapter.method('closeChangePassword', function() {

12
app/api/.htaccess Normal file
View File

@@ -0,0 +1,12 @@
<IfModule mod_rewrite.c>
Options +FollowSymlinks
RewriteEngine On
# Explicitly disable rewriting for front controllers
RewriteRule ^index.php - [L]
RewriteCond %{REQUEST_FILENAME} !-f
# Change below before deploying to production
RewriteRule ^(.*)$ index.php [QSA,L]
</IfModule>

3
app/api/index.php Normal file
View File

@@ -0,0 +1,3 @@
<?php
include __DIR__.'/../config.php';
include (APP_BASE_PATH.'rest.php');

View File

@@ -13,10 +13,10 @@ if(!defined('HOME_LINK_OTHERS')){
} }
//Version //Version
define('VERSION', '20.2.0.OS'); define('VERSION', '20.3.0.OS');
define('CACHE_VALUE', '20.2.0.OS'); define('CACHE_VALUE', '20.3.0.OS');
define('VERSION_NUMBER', '2020'); define('VERSION_NUMBER', '2030');
define('VERSION_DATE', '28/09/2017'); define('VERSION_DATE', '26/11/2017');
if(!defined('CONTACT_EMAIL')){define('CONTACT_EMAIL','icehrm@gamonoid.com');} if(!defined('CONTACT_EMAIL')){define('CONTACT_EMAIL','icehrm@gamonoid.com');}
if(!defined('KEY_PREFIX')){define('KEY_PREFIX','IceHrm');} if(!defined('KEY_PREFIX')){define('KEY_PREFIX','IceHrm');}

View File

@@ -40,20 +40,20 @@ function checkFileType (elementName, fileTypes) {
if (fileElement.value.lastIndexOf(".") > 0) { if (fileElement.value.lastIndexOf(".") > 0) {
fileExtension = fileElement.value.substring(fileElement.value.lastIndexOf(".") + 1, fileElement.value.length); fileExtension = fileElement.value.substring(fileElement.value.lastIndexOf(".") + 1, fileElement.value.length);
} }
fileExtension = fileExtension.toLowerCase(); fileExtension = fileExtension.toLowerCase();
var allowed = fileTypes.split(","); var allowed = fileTypes.split(",");
if (allowed.indexOf(fileExtension) < 0) { if (allowed.indexOf(fileExtension) < 0) {
fileElement.value = ""; fileElement.value = "";
alert('Selected file type is not supported'); alert('Selected file type is not supported');
clearFileElement(elementName); clearFileElement(elementName);
return false; return false;
} }
return true; return true;
} }
function clearFileElement (elementName) { function clearFileElement (elementName) {
@@ -76,4 +76,4 @@ function clearFileElement (elementName) {
</div> </div>
<script type="text/javascript">document.body.style.overflow = 'hidden';</script> <script type="text/javascript">document.body.style.overflow = 'hidden';</script>
</body> </body>
</html> </html>

BIN
images/file-icons/json.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 559 B

View File

@@ -4,7 +4,8 @@
"twig/twig": "1.23.*", "twig/twig": "1.23.*",
"gettext/gettext": "4.0.0", "gettext/gettext": "4.0.0",
"consolidation/robo": "~1", "consolidation/robo": "~1",
"filp/whoops": "~2.1" "filp/whoops": "~2.1",
"swiftmailer/swiftmailer": "^6.0"
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": "5.5.*" "phpunit/phpunit": "5.5.*"

View File

@@ -1,10 +1,11 @@
{ {
"_readme": [ "_readme": [
"This file locks the dependencies of your project to a known state", "This file locks the dependencies of your project to a known state",
"Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"hash": "eb7486b98c829f999be2a3a5ce5d48b4", "hash": "1944dee39b7f749b311e58061b00f233",
"content-hash": "7a06e9dbeabacf6aec7777ff8b9d4891",
"packages": [ "packages": [
{ {
"name": "consolidation/annotated-command", "name": "consolidation/annotated-command",
@@ -258,6 +259,117 @@
"description": "Promoting the interoperability of container objects (DIC, SL, etc.)", "description": "Promoting the interoperability of container objects (DIC, SL, etc.)",
"time": "2014-12-30 15:22:37" "time": "2014-12-30 15:22:37"
}, },
{
"name": "doctrine/lexer",
"version": "v1.0.1",
"source": {
"type": "git",
"url": "https://github.com/doctrine/lexer.git",
"reference": "83893c552fd2045dd78aef794c31e694c37c0b8c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/lexer/zipball/83893c552fd2045dd78aef794c31e694c37c0b8c",
"reference": "83893c552fd2045dd78aef794c31e694c37c0b8c",
"shasum": ""
},
"require": {
"php": ">=5.3.2"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-0": {
"Doctrine\\Common\\Lexer\\": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com"
},
{
"name": "Johannes Schmitt",
"email": "schmittjoh@gmail.com"
}
],
"description": "Base library for a lexer that can be used in Top-Down, Recursive Descent Parsers.",
"homepage": "http://www.doctrine-project.org",
"keywords": [
"lexer",
"parser"
],
"time": "2014-09-09 13:34:57"
},
{
"name": "egulias/email-validator",
"version": "2.1.3",
"source": {
"type": "git",
"url": "https://github.com/egulias/EmailValidator.git",
"reference": "1bec00a10039b823cc94eef4eddd47dcd3b2ca04"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/egulias/EmailValidator/zipball/1bec00a10039b823cc94eef4eddd47dcd3b2ca04",
"reference": "1bec00a10039b823cc94eef4eddd47dcd3b2ca04",
"shasum": ""
},
"require": {
"doctrine/lexer": "^1.0.1",
"php": ">= 5.5"
},
"require-dev": {
"dominicsayers/isemail": "dev-master",
"phpunit/phpunit": "^4.8.35",
"satooshi/php-coveralls": "^1.0.1"
},
"suggest": {
"ext-intl": "PHP Internationalization Libraries are required to use the SpoofChecking validation"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Egulias\\EmailValidator\\": "EmailValidator"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Eduardo Gulias Davis"
}
],
"description": "A library for validating emails against several RFCs",
"homepage": "https://github.com/egulias/EmailValidator",
"keywords": [
"email",
"emailvalidation",
"emailvalidator",
"validation",
"validator"
],
"time": "2017-11-15 23:40:40"
},
{ {
"name": "filp/whoops", "name": "filp/whoops",
"version": "2.1.10", "version": "2.1.10",
@@ -763,6 +875,61 @@
], ],
"time": "2016-10-10 12:19:37" "time": "2016-10-10 12:19:37"
}, },
{
"name": "swiftmailer/swiftmailer",
"version": "v6.0.2",
"source": {
"type": "git",
"url": "https://github.com/swiftmailer/swiftmailer.git",
"reference": "412333372fb6c8ffb65496a2bbd7321af75733fc"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/412333372fb6c8ffb65496a2bbd7321af75733fc",
"reference": "412333372fb6c8ffb65496a2bbd7321af75733fc",
"shasum": ""
},
"require": {
"egulias/email-validator": "~2.0",
"php": ">=7.0.0"
},
"require-dev": {
"mockery/mockery": "~0.9.1",
"symfony/phpunit-bridge": "~3.3@dev"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "6.0-dev"
}
},
"autoload": {
"files": [
"lib/swift_required.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Chris Corbyn"
},
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
}
],
"description": "Swiftmailer, free feature-rich PHP mailer",
"homepage": "http://swiftmailer.symfony.com",
"keywords": [
"email",
"mail",
"mailer"
],
"time": "2017-09-30 22:39:41"
},
{ {
"name": "symfony/console", "name": "symfony/console",
"version": "v3.1.6", "version": "v3.1.6",

View File

@@ -4,4 +4,4 @@
require_once __DIR__ . '/composer' . '/autoload_real.php'; require_once __DIR__ . '/composer' . '/autoload_real.php';
return ComposerAutoloaderInit17bd94f80a35033ddd449fc4168708d6::getLoader(); return ComposerAutoloaderInita01cedac3fb3abb6b395843685a2b9da::getLoader();

View File

@@ -13,9 +13,7 @@
namespace Composer\Autoload; namespace Composer\Autoload;
/** /**
* ClassLoader implements a PSR-0 class loader * ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
*
* See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md
* *
* $loader = new \Composer\Autoload\ClassLoader(); * $loader = new \Composer\Autoload\ClassLoader();
* *
@@ -39,6 +37,8 @@ namespace Composer\Autoload;
* *
* @author Fabien Potencier <fabien@symfony.com> * @author Fabien Potencier <fabien@symfony.com>
* @author Jordi Boggiano <j.boggiano@seld.be> * @author Jordi Boggiano <j.boggiano@seld.be>
* @see http://www.php-fig.org/psr/psr-0/
* @see http://www.php-fig.org/psr/psr-4/
*/ */
class ClassLoader class ClassLoader
{ {
@@ -147,7 +147,7 @@ class ClassLoader
* appending or prepending to the ones previously set for this namespace. * appending or prepending to the ones previously set for this namespace.
* *
* @param string $prefix The prefix/namespace, with trailing '\\' * @param string $prefix The prefix/namespace, with trailing '\\'
* @param array|string $paths The PSR-0 base directories * @param array|string $paths The PSR-4 base directories
* @param bool $prepend Whether to prepend the directories * @param bool $prepend Whether to prepend the directories
* *
* @throws \InvalidArgumentException * @throws \InvalidArgumentException

View File

@@ -6,5 +6,6 @@ $vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir); $baseDir = dirname($vendorDir);
return array( return array(
$vendorDir . '/symfony/polyfill-mbstring/bootstrap.php', '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php',
'2c102faa651ef8ea5874edb585946bce' => $vendorDir . '/swiftmailer/swiftmailer/lib/swift_required.php',
); );

View File

@@ -9,4 +9,5 @@ return array(
'Twig_' => array($vendorDir . '/twig/twig/lib'), 'Twig_' => array($vendorDir . '/twig/twig/lib'),
'Prophecy\\' => array($vendorDir . '/phpspec/prophecy/src'), 'Prophecy\\' => array($vendorDir . '/phpspec/prophecy/src'),
'PHPDocsMD' => array($vendorDir . '/victorjonsson/markdowndocs/src'), 'PHPDocsMD' => array($vendorDir . '/victorjonsson/markdowndocs/src'),
'Doctrine\\Common\\Lexer\\' => array($vendorDir . '/doctrine/lexer/lib'),
); );

View File

@@ -24,6 +24,7 @@ return array(
'Interop\\Container\\' => array($vendorDir . '/container-interop/container-interop/src/Interop/Container'), 'Interop\\Container\\' => array($vendorDir . '/container-interop/container-interop/src/Interop/Container'),
'Gettext\\Languages\\' => array($vendorDir . '/gettext/languages/src'), 'Gettext\\Languages\\' => array($vendorDir . '/gettext/languages/src'),
'Gettext\\' => array($vendorDir . '/gettext/gettext/src'), 'Gettext\\' => array($vendorDir . '/gettext/gettext/src'),
'Egulias\\EmailValidator\\' => array($vendorDir . '/egulias/email-validator/EmailValidator'),
'Doctrine\\Instantiator\\' => array($vendorDir . '/doctrine/instantiator/src/Doctrine/Instantiator'), 'Doctrine\\Instantiator\\' => array($vendorDir . '/doctrine/instantiator/src/Doctrine/Instantiator'),
'DeepCopy\\' => array($vendorDir . '/myclabs/deep-copy/src/DeepCopy'), 'DeepCopy\\' => array($vendorDir . '/myclabs/deep-copy/src/DeepCopy'),
'Consolidation\\OutputFormatters\\' => array($vendorDir . '/consolidation/output-formatters/src'), 'Consolidation\\OutputFormatters\\' => array($vendorDir . '/consolidation/output-formatters/src'),

View File

@@ -2,7 +2,7 @@
// autoload_real.php @generated by Composer // autoload_real.php @generated by Composer
class ComposerAutoloaderInit17bd94f80a35033ddd449fc4168708d6 class ComposerAutoloaderInita01cedac3fb3abb6b395843685a2b9da
{ {
private static $loader; private static $loader;
@@ -19,37 +19,52 @@ class ComposerAutoloaderInit17bd94f80a35033ddd449fc4168708d6
return self::$loader; return self::$loader;
} }
spl_autoload_register(array('ComposerAutoloaderInit17bd94f80a35033ddd449fc4168708d6', 'loadClassLoader'), true, true); spl_autoload_register(array('ComposerAutoloaderInita01cedac3fb3abb6b395843685a2b9da', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader(); self::$loader = $loader = new \Composer\Autoload\ClassLoader();
spl_autoload_unregister(array('ComposerAutoloaderInit17bd94f80a35033ddd449fc4168708d6', 'loadClassLoader')); spl_autoload_unregister(array('ComposerAutoloaderInita01cedac3fb3abb6b395843685a2b9da', 'loadClassLoader'));
$map = require __DIR__ . '/autoload_namespaces.php'; $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION');
foreach ($map as $namespace => $path) { if ($useStaticLoader) {
$loader->set($namespace, $path); require_once __DIR__ . '/autoload_static.php';
}
$map = require __DIR__ . '/autoload_psr4.php'; call_user_func(\Composer\Autoload\ComposerStaticInita01cedac3fb3abb6b395843685a2b9da::getInitializer($loader));
foreach ($map as $namespace => $path) { } else {
$loader->setPsr4($namespace, $path); $map = require __DIR__ . '/autoload_namespaces.php';
} foreach ($map as $namespace => $path) {
$loader->set($namespace, $path);
}
$classMap = require __DIR__ . '/autoload_classmap.php'; $map = require __DIR__ . '/autoload_psr4.php';
if ($classMap) { foreach ($map as $namespace => $path) {
$loader->addClassMap($classMap); $loader->setPsr4($namespace, $path);
}
$classMap = require __DIR__ . '/autoload_classmap.php';
if ($classMap) {
$loader->addClassMap($classMap);
}
} }
$loader->register(true); $loader->register(true);
$includeFiles = require __DIR__ . '/autoload_files.php'; if ($useStaticLoader) {
foreach ($includeFiles as $file) { $includeFiles = Composer\Autoload\ComposerStaticInita01cedac3fb3abb6b395843685a2b9da::$files;
composerRequire17bd94f80a35033ddd449fc4168708d6($file); } else {
$includeFiles = require __DIR__ . '/autoload_files.php';
}
foreach ($includeFiles as $fileIdentifier => $file) {
composerRequirea01cedac3fb3abb6b395843685a2b9da($fileIdentifier, $file);
} }
return $loader; return $loader;
} }
} }
function composerRequire17bd94f80a35033ddd449fc4168708d6($file) function composerRequirea01cedac3fb3abb6b395843685a2b9da($fileIdentifier, $file)
{ {
require $file; if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
require $file;
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
}
} }

View File

@@ -4,10 +4,11 @@
namespace Composer\Autoload; namespace Composer\Autoload;
class ComposerStaticInit91d733469d809ee1828b45ab2da48a10 class ComposerStaticInita01cedac3fb3abb6b395843685a2b9da
{ {
public static $files = array ( public static $files = array (
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php', '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
'2c102faa651ef8ea5874edb585946bce' => __DIR__ . '/..' . '/swiftmailer/swiftmailer/lib/swift_required.php',
); );
public static $prefixLengthsPsr4 = array ( public static $prefixLengthsPsr4 = array (
@@ -17,6 +18,7 @@ class ComposerStaticInit91d733469d809ee1828b45ab2da48a10
), ),
'W' => 'W' =>
array ( array (
'Whoops\\' => 7,
'Webmozart\\Assert\\' => 17, 'Webmozart\\Assert\\' => 17,
), ),
'S' => 'S' =>
@@ -55,6 +57,10 @@ class ComposerStaticInit91d733469d809ee1828b45ab2da48a10
'Gettext\\Languages\\' => 18, 'Gettext\\Languages\\' => 18,
'Gettext\\' => 8, 'Gettext\\' => 8,
), ),
'E' =>
array (
'Egulias\\EmailValidator\\' => 23,
),
'D' => 'D' =>
array ( array (
'Doctrine\\Instantiator\\' => 22, 'Doctrine\\Instantiator\\' => 22,
@@ -75,6 +81,10 @@ class ComposerStaticInit91d733469d809ee1828b45ab2da48a10
1 => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src', 1 => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src',
2 => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src', 2 => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src',
), ),
'Whoops\\' =>
array (
0 => __DIR__ . '/..' . '/filp/whoops/src/Whoops',
),
'Webmozart\\Assert\\' => 'Webmozart\\Assert\\' =>
array ( array (
0 => __DIR__ . '/..' . '/webmozart/assert/src', 0 => __DIR__ . '/..' . '/webmozart/assert/src',
@@ -139,6 +149,10 @@ class ComposerStaticInit91d733469d809ee1828b45ab2da48a10
array ( array (
0 => __DIR__ . '/..' . '/gettext/gettext/src', 0 => __DIR__ . '/..' . '/gettext/gettext/src',
), ),
'Egulias\\EmailValidator\\' =>
array (
0 => __DIR__ . '/..' . '/egulias/email-validator/EmailValidator',
),
'Doctrine\\Instantiator\\' => 'Doctrine\\Instantiator\\' =>
array ( array (
0 => __DIR__ . '/..' . '/doctrine/instantiator/src/Doctrine/Instantiator', 0 => __DIR__ . '/..' . '/doctrine/instantiator/src/Doctrine/Instantiator',
@@ -161,6 +175,10 @@ class ComposerStaticInit91d733469d809ee1828b45ab2da48a10
), ),
); );
public static $fallbackDirsPsr4 = array (
0 => __DIR__ . '/../..' . '/../../src',
);
public static $prefixesPsr0 = array ( public static $prefixesPsr0 = array (
'T' => 'T' =>
array ( array (
@@ -180,6 +198,13 @@ class ComposerStaticInit91d733469d809ee1828b45ab2da48a10
0 => __DIR__ . '/..' . '/victorjonsson/markdowndocs/src', 0 => __DIR__ . '/..' . '/victorjonsson/markdowndocs/src',
), ),
), ),
'D' =>
array (
'Doctrine\\Common\\Lexer\\' =>
array (
0 => __DIR__ . '/..' . '/doctrine/lexer/lib',
),
),
); );
public static $classMap = array ( public static $classMap = array (
@@ -644,10 +669,11 @@ class ComposerStaticInit91d733469d809ee1828b45ab2da48a10
public static function getInitializer(ClassLoader $loader) public static function getInitializer(ClassLoader $loader)
{ {
return \Closure::bind(function () use ($loader) { return \Closure::bind(function () use ($loader) {
$loader->prefixLengthsPsr4 = ComposerStaticInit91d733469d809ee1828b45ab2da48a10::$prefixLengthsPsr4; $loader->prefixLengthsPsr4 = ComposerStaticInita01cedac3fb3abb6b395843685a2b9da::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInit91d733469d809ee1828b45ab2da48a10::$prefixDirsPsr4; $loader->prefixDirsPsr4 = ComposerStaticInita01cedac3fb3abb6b395843685a2b9da::$prefixDirsPsr4;
$loader->prefixesPsr0 = ComposerStaticInit91d733469d809ee1828b45ab2da48a10::$prefixesPsr0; $loader->fallbackDirsPsr4 = ComposerStaticInita01cedac3fb3abb6b395843685a2b9da::$fallbackDirsPsr4;
$loader->classMap = ComposerStaticInit91d733469d809ee1828b45ab2da48a10::$classMap; $loader->prefixesPsr0 = ComposerStaticInita01cedac3fb3abb6b395843685a2b9da::$prefixesPsr0;
$loader->classMap = ComposerStaticInita01cedac3fb3abb6b395843685a2b9da::$classMap;
}, null, ClassLoader::class); }, null, ClassLoader::class);
} }

View File

@@ -2490,5 +2490,177 @@
"whoops", "whoops",
"zf2" "zf2"
] ]
},
{
"name": "doctrine/lexer",
"version": "v1.0.1",
"version_normalized": "1.0.1.0",
"source": {
"type": "git",
"url": "https://github.com/doctrine/lexer.git",
"reference": "83893c552fd2045dd78aef794c31e694c37c0b8c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/lexer/zipball/83893c552fd2045dd78aef794c31e694c37c0b8c",
"reference": "83893c552fd2045dd78aef794c31e694c37c0b8c",
"shasum": ""
},
"require": {
"php": ">=5.3.2"
},
"time": "2014-09-09 13:34:57",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-0": {
"Doctrine\\Common\\Lexer\\": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com"
},
{
"name": "Johannes Schmitt",
"email": "schmittjoh@gmail.com"
}
],
"description": "Base library for a lexer that can be used in Top-Down, Recursive Descent Parsers.",
"homepage": "http://www.doctrine-project.org",
"keywords": [
"lexer",
"parser"
]
},
{
"name": "egulias/email-validator",
"version": "2.1.3",
"version_normalized": "2.1.3.0",
"source": {
"type": "git",
"url": "https://github.com/egulias/EmailValidator.git",
"reference": "1bec00a10039b823cc94eef4eddd47dcd3b2ca04"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/egulias/EmailValidator/zipball/1bec00a10039b823cc94eef4eddd47dcd3b2ca04",
"reference": "1bec00a10039b823cc94eef4eddd47dcd3b2ca04",
"shasum": ""
},
"require": {
"doctrine/lexer": "^1.0.1",
"php": ">= 5.5"
},
"require-dev": {
"dominicsayers/isemail": "dev-master",
"phpunit/phpunit": "^4.8.35",
"satooshi/php-coveralls": "^1.0.1"
},
"suggest": {
"ext-intl": "PHP Internationalization Libraries are required to use the SpoofChecking validation"
},
"time": "2017-11-15 23:40:40",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.0.x-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"Egulias\\EmailValidator\\": "EmailValidator"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Eduardo Gulias Davis"
}
],
"description": "A library for validating emails against several RFCs",
"homepage": "https://github.com/egulias/EmailValidator",
"keywords": [
"email",
"emailvalidation",
"emailvalidator",
"validation",
"validator"
]
},
{
"name": "swiftmailer/swiftmailer",
"version": "v6.0.2",
"version_normalized": "6.0.2.0",
"source": {
"type": "git",
"url": "https://github.com/swiftmailer/swiftmailer.git",
"reference": "412333372fb6c8ffb65496a2bbd7321af75733fc"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/412333372fb6c8ffb65496a2bbd7321af75733fc",
"reference": "412333372fb6c8ffb65496a2bbd7321af75733fc",
"shasum": ""
},
"require": {
"egulias/email-validator": "~2.0",
"php": ">=7.0.0"
},
"require-dev": {
"mockery/mockery": "~0.9.1",
"symfony/phpunit-bridge": "~3.3@dev"
},
"time": "2017-09-30 22:39:41",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "6.0-dev"
}
},
"installation-source": "dist",
"autoload": {
"files": [
"lib/swift_required.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Chris Corbyn"
},
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
}
],
"description": "Swiftmailer, free feature-rich PHP mailer",
"homepage": "http://swiftmailer.symfony.com",
"keywords": [
"email",
"mail",
"mailer"
]
} }
] ]

View File

@@ -0,0 +1,19 @@
Copyright (c) 2006-2013 Doctrine Project
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,5 @@
# Doctrine Lexer
Base library for a lexer that can be used in Top-Down, Recursive Descent Parsers.
This lexer is used in Doctrine Annotations and in Doctrine ORM (DQL).

View File

@@ -0,0 +1,24 @@
{
"name": "doctrine/lexer",
"type": "library",
"description": "Base library for a lexer that can be used in Top-Down, Recursive Descent Parsers.",
"keywords": ["lexer", "parser"],
"homepage": "http://www.doctrine-project.org",
"license": "MIT",
"authors": [
{"name": "Guilherme Blanco", "email": "guilhermeblanco@gmail.com"},
{"name": "Roman Borschel", "email": "roman@code-factory.org"},
{"name": "Johannes Schmitt", "email": "schmittjoh@gmail.com"}
],
"require": {
"php": ">=5.3.2"
},
"autoload": {
"psr-0": { "Doctrine\\Common\\Lexer\\": "lib/" }
},
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
}
}

View File

@@ -0,0 +1,327 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\Common\Lexer;
/**
* Base class for writing simple lexers, i.e. for creating small DSLs.
*
* @since 2.0
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @author Jonathan Wage <jonwage@gmail.com>
* @author Roman Borschel <roman@code-factory.org>
*/
abstract class AbstractLexer
{
/**
* Lexer original input string.
*
* @var string
*/
private $input;
/**
* Array of scanned tokens.
*
* Each token is an associative array containing three items:
* - 'value' : the string value of the token in the input string
* - 'type' : the type of the token (identifier, numeric, string, input
* parameter, none)
* - 'position' : the position of the token in the input string
*
* @var array
*/
private $tokens = array();
/**
* Current lexer position in input string.
*
* @var integer
*/
private $position = 0;
/**
* Current peek of current lexer position.
*
* @var integer
*/
private $peek = 0;
/**
* The next token in the input.
*
* @var array
*/
public $lookahead;
/**
* The last matched/seen token.
*
* @var array
*/
public $token;
/**
* Sets the input data to be tokenized.
*
* The Lexer is immediately reset and the new input tokenized.
* Any unprocessed tokens from any previous input are lost.
*
* @param string $input The input to be tokenized.
*
* @return void
*/
public function setInput($input)
{
$this->input = $input;
$this->tokens = array();
$this->reset();
$this->scan($input);
}
/**
* Resets the lexer.
*
* @return void
*/
public function reset()
{
$this->lookahead = null;
$this->token = null;
$this->peek = 0;
$this->position = 0;
}
/**
* Resets the peek pointer to 0.
*
* @return void
*/
public function resetPeek()
{
$this->peek = 0;
}
/**
* Resets the lexer position on the input to the given position.
*
* @param integer $position Position to place the lexical scanner.
*
* @return void
*/
public function resetPosition($position = 0)
{
$this->position = $position;
}
/**
* Retrieve the original lexer's input until a given position.
*
* @param integer $position
*
* @return string
*/
public function getInputUntilPosition($position)
{
return substr($this->input, 0, $position);
}
/**
* Checks whether a given token matches the current lookahead.
*
* @param integer|string $token
*
* @return boolean
*/
public function isNextToken($token)
{
return null !== $this->lookahead && $this->lookahead['type'] === $token;
}
/**
* Checks whether any of the given tokens matches the current lookahead.
*
* @param array $tokens
*
* @return boolean
*/
public function isNextTokenAny(array $tokens)
{
return null !== $this->lookahead && in_array($this->lookahead['type'], $tokens, true);
}
/**
* Moves to the next token in the input string.
*
* @return boolean
*/
public function moveNext()
{
$this->peek = 0;
$this->token = $this->lookahead;
$this->lookahead = (isset($this->tokens[$this->position]))
? $this->tokens[$this->position++] : null;
return $this->lookahead !== null;
}
/**
* Tells the lexer to skip input tokens until it sees a token with the given value.
*
* @param string $type The token type to skip until.
*
* @return void
*/
public function skipUntil($type)
{
while ($this->lookahead !== null && $this->lookahead['type'] !== $type) {
$this->moveNext();
}
}
/**
* Checks if given value is identical to the given token.
*
* @param mixed $value
* @param integer $token
*
* @return boolean
*/
public function isA($value, $token)
{
return $this->getType($value) === $token;
}
/**
* Moves the lookahead token forward.
*
* @return array|null The next token or NULL if there are no more tokens ahead.
*/
public function peek()
{
if (isset($this->tokens[$this->position + $this->peek])) {
return $this->tokens[$this->position + $this->peek++];
} else {
return null;
}
}
/**
* Peeks at the next token, returns it and immediately resets the peek.
*
* @return array|null The next token or NULL if there are no more tokens ahead.
*/
public function glimpse()
{
$peek = $this->peek();
$this->peek = 0;
return $peek;
}
/**
* Scans the input string for tokens.
*
* @param string $input A query string.
*
* @return void
*/
protected function scan($input)
{
static $regex;
if ( ! isset($regex)) {
$regex = sprintf(
'/(%s)|%s/%s',
implode(')|(', $this->getCatchablePatterns()),
implode('|', $this->getNonCatchablePatterns()),
$this->getModifiers()
);
}
$flags = PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_OFFSET_CAPTURE;
$matches = preg_split($regex, $input, -1, $flags);
foreach ($matches as $match) {
// Must remain before 'value' assignment since it can change content
$type = $this->getType($match[0]);
$this->tokens[] = array(
'value' => $match[0],
'type' => $type,
'position' => $match[1],
);
}
}
/**
* Gets the literal for a given token.
*
* @param integer $token
*
* @return string
*/
public function getLiteral($token)
{
$className = get_class($this);
$reflClass = new \ReflectionClass($className);
$constants = $reflClass->getConstants();
foreach ($constants as $name => $value) {
if ($value === $token) {
return $className . '::' . $name;
}
}
return $token;
}
/**
* Regex modifiers
*
* @return string
*/
protected function getModifiers()
{
return 'i';
}
/**
* Lexical catchable patterns.
*
* @return array
*/
abstract protected function getCatchablePatterns();
/**
* Lexical non-catchable patterns.
*
* @return array
*/
abstract protected function getNonCatchablePatterns();
/**
* Retrieve token type. Also processes the token value if necessary.
*
* @param string $value
*
* @return integer
*/
abstract protected function getType(&$value);
}

View File

@@ -0,0 +1,221 @@
<?php
namespace Egulias\EmailValidator;
use Doctrine\Common\Lexer\AbstractLexer;
class EmailLexer extends AbstractLexer
{
//ASCII values
const C_DEL = 127;
const C_NUL = 0;
const S_AT = 64;
const S_BACKSLASH = 92;
const S_DOT = 46;
const S_DQUOTE = 34;
const S_OPENPARENTHESIS = 49;
const S_CLOSEPARENTHESIS = 261;
const S_OPENBRACKET = 262;
const S_CLOSEBRACKET = 263;
const S_HYPHEN = 264;
const S_COLON = 265;
const S_DOUBLECOLON = 266;
const S_SP = 267;
const S_HTAB = 268;
const S_CR = 269;
const S_LF = 270;
const S_IPV6TAG = 271;
const S_LOWERTHAN = 272;
const S_GREATERTHAN = 273;
const S_COMMA = 274;
const S_SEMICOLON = 275;
const S_OPENQBRACKET = 276;
const S_CLOSEQBRACKET = 277;
const S_SLASH = 278;
const S_EMPTY = null;
const GENERIC = 300;
const CRLF = 301;
const INVALID = 302;
const ASCII_INVALID_FROM = 127;
const ASCII_INVALID_TO = 199;
/**
* US-ASCII visible characters not valid for atext (@link http://tools.ietf.org/html/rfc5322#section-3.2.3)
*
* @var array
*/
protected $charValue = array(
'(' => self::S_OPENPARENTHESIS,
')' => self::S_CLOSEPARENTHESIS,
'<' => self::S_LOWERTHAN,
'>' => self::S_GREATERTHAN,
'[' => self::S_OPENBRACKET,
']' => self::S_CLOSEBRACKET,
':' => self::S_COLON,
';' => self::S_SEMICOLON,
'@' => self::S_AT,
'\\' => self::S_BACKSLASH,
'/' => self::S_SLASH,
',' => self::S_COMMA,
'.' => self::S_DOT,
'"' => self::S_DQUOTE,
'-' => self::S_HYPHEN,
'::' => self::S_DOUBLECOLON,
' ' => self::S_SP,
"\t" => self::S_HTAB,
"\r" => self::S_CR,
"\n" => self::S_LF,
"\r\n" => self::CRLF,
'IPv6' => self::S_IPV6TAG,
'{' => self::S_OPENQBRACKET,
'}' => self::S_CLOSEQBRACKET,
'' => self::S_EMPTY,
'\0' => self::C_NUL,
);
protected $hasInvalidTokens = false;
protected $previous;
public function reset()
{
$this->hasInvalidTokens = false;
parent::reset();
}
public function hasInvalidTokens()
{
return $this->hasInvalidTokens;
}
/**
* @param $type
* @throws \UnexpectedValueException
* @return boolean
*/
public function find($type)
{
$search = clone $this;
$search->skipUntil($type);
if (!$search->lookahead) {
throw new \UnexpectedValueException($type . ' not found');
}
return true;
}
/**
* getPrevious
*
* @return array token
*/
public function getPrevious()
{
return $this->previous;
}
/**
* moveNext
*
* @return boolean
*/
public function moveNext()
{
$this->previous = $this->token;
return parent::moveNext();
}
/**
* Lexical catchable patterns.
*
* @return string[]
*/
protected function getCatchablePatterns()
{
return array(
'[a-zA-Z_]+[46]?', //ASCII and domain literal
'[^\x00-\x7F]', //UTF-8
'[0-9]+',
'\r\n',
'::',
'\s+?',
'.',
);
}
/**
* Lexical non-catchable patterns.
*
* @return string[]
*/
protected function getNonCatchablePatterns()
{
return array('[\xA0-\xff]+');
}
/**
* Retrieve token type. Also processes the token value if necessary.
*
* @param string $value
* @throws \InvalidArgumentException
* @return integer
*/
protected function getType(&$value)
{
if ($this->isNullType($value)) {
return self::C_NUL;
}
if ($this->isValid($value)) {
return $this->charValue[$value];
}
if ($this->isUTF8Invalid($value)) {
$this->hasInvalidTokens = true;
return self::INVALID;
}
return self::GENERIC;
}
protected function isValid($value)
{
if (isset($this->charValue[$value])) {
return true;
}
return false;
}
/**
* @param $value
* @return bool
*/
protected function isNullType($value)
{
if ($value === "\0") {
return true;
}
return false;
}
/**
* @param $value
* @return bool
*/
protected function isUTF8Invalid($value)
{
if (preg_match('/\p{Cc}+/u', $value)) {
return true;
}
return false;
}
protected function getModifiers()
{
return 'iu';
}
}

View File

@@ -0,0 +1,104 @@
<?php
namespace Egulias\EmailValidator;
use Egulias\EmailValidator\Exception\ExpectingATEXT;
use Egulias\EmailValidator\Exception\NoLocalPart;
use Egulias\EmailValidator\Parser\DomainPart;
use Egulias\EmailValidator\Parser\LocalPart;
use Egulias\EmailValidator\Warning\EmailTooLong;
/**
* EmailParser
*
* @author Eduardo Gulias Davis <me@egulias.com>
*/
class EmailParser
{
const EMAIL_MAX_LENGTH = 254;
protected $warnings;
protected $domainPart = '';
protected $localPart = '';
protected $lexer;
protected $localPartParser;
protected $domainPartParser;
public function __construct(EmailLexer $lexer)
{
$this->lexer = $lexer;
$this->localPartParser = new LocalPart($this->lexer);
$this->domainPartParser = new DomainPart($this->lexer);
$this->warnings = new \SplObjectStorage();
}
/**
* @param $str
* @return array
*/
public function parse($str)
{
$this->lexer->setInput($str);
if (!$this->hasAtToken()) {
throw new NoLocalPart();
}
$this->localPartParser->parse($str);
$this->domainPartParser->parse($str);
$this->setParts($str);
if ($this->lexer->hasInvalidTokens()) {
throw new ExpectingATEXT();
}
return array('local' => $this->localPart, 'domain' => $this->domainPart);
}
public function getWarnings()
{
$localPartWarnings = $this->localPartParser->getWarnings();
$domainPartWarnings = $this->domainPartParser->getWarnings();
$this->warnings = array_merge($localPartWarnings, $domainPartWarnings);
$this->addLongEmailWarning($this->localPart, $this->domainPart);
return $this->warnings;
}
public function getParsedDomainPart()
{
return $this->domainPart;
}
protected function setParts($email)
{
$parts = explode('@', $email);
$this->domainPart = $this->domainPartParser->getDomainPart();
$this->localPart = $parts[0];
}
protected function hasAtToken()
{
$this->lexer->moveNext();
$this->lexer->moveNext();
if ($this->lexer->token['type'] === EmailLexer::S_AT) {
return false;
}
return true;
}
/**
* @param string $localPart
* @param string $parsedDomainPart
*/
protected function addLongEmailWarning($localPart, $parsedDomainPart)
{
if (strlen($localPart . '@' . $parsedDomainPart) > self::EMAIL_MAX_LENGTH) {
$this->warnings[EmailTooLong::CODE] = new EmailTooLong();
}
}
}

View File

@@ -0,0 +1,67 @@
<?php
namespace Egulias\EmailValidator;
use Egulias\EmailValidator\Exception\InvalidEmail;
use Egulias\EmailValidator\Validation\EmailValidation;
class EmailValidator
{
/**
* @var EmailLexer
*/
private $lexer;
/**
* @var array
*/
protected $warnings;
/**
* @var InvalidEmail
*/
protected $error;
public function __construct()
{
$this->lexer = new EmailLexer();
}
/**
* @param $email
* @param EmailValidation $emailValidation
* @return bool
*/
public function isValid($email, EmailValidation $emailValidation)
{
$isValid = $emailValidation->isValid($email, $this->lexer);
$this->warnings = $emailValidation->getWarnings();
$this->error = $emailValidation->getError();
return $isValid;
}
/**
* @return boolean
*/
public function hasWarnings()
{
return !empty($this->warnings);
}
/**
* @return array
*/
public function getWarnings()
{
return $this->warnings;
}
/**
* @return InvalidEmail
*/
public function getError()
{
return $this->error;
}
}

View File

@@ -0,0 +1,9 @@
<?php
namespace Egulias\EmailValidator\Exception;
class AtextAfterCFWS extends InvalidEmail
{
const CODE = 133;
const REASON = "ATEXT found after CFWS";
}

View File

@@ -0,0 +1,9 @@
<?php
namespace Egulias\EmailValidator\Exception;
class CRLFAtTheEnd extends InvalidEmail
{
const CODE = 149;
const REASON = "CRLF at the end";
}

View File

@@ -0,0 +1,9 @@
<?php
namespace Egulias\EmailValidator\Exception;
class CRLFX2 extends InvalidEmail
{
const CODE = 148;
const REASON = "Folding whitespace CR LF found twice";
}

View File

@@ -0,0 +1,9 @@
<?php
namespace Egulias\EmailValidator\Exception;
class CRNoLF extends InvalidEmail
{
const CODE = 150;
const REASON = "Missing LF after CR";
}

View File

@@ -0,0 +1,9 @@
<?php
namespace Egulias\EmailValidator\Exception;
class CharNotAllowed extends InvalidEmail
{
const CODE = 201;
const REASON = "Non allowed character in domain";
}

View File

@@ -0,0 +1,9 @@
<?php
namespace Egulias\EmailValidator\Exception;
class CommaInDomain extends InvalidEmail
{
const CODE = 200;
const REASON = "Comma ',' is not allowed in domain part";
}

View File

@@ -0,0 +1,9 @@
<?php
namespace Egulias\EmailValidator\Exception;
class ConsecutiveAt extends InvalidEmail
{
const CODE = 128;
const REASON = "Consecutive AT";
}

View File

@@ -0,0 +1,9 @@
<?php
namespace Egulias\EmailValidator\Exception;
class ConsecutiveDot extends InvalidEmail
{
const CODE = 132;
const REASON = "Consecutive DOT";
}

View File

@@ -0,0 +1,9 @@
<?php
namespace Egulias\EmailValidator\Exception;
class DomainHyphened extends InvalidEmail
{
const CODE = 144;
const REASON = "Hyphen found in domain";
}

View File

@@ -0,0 +1,9 @@
<?php
namespace Egulias\EmailValidator\Exception;
class DotAtEnd extends InvalidEmail
{
const CODE = 142;
const REASON = "Dot at the end";
}

View File

@@ -0,0 +1,9 @@
<?php
namespace Egulias\EmailValidator\Exception;
class DotAtStart extends InvalidEmail
{
const CODE = 141;
const REASON = "Found DOT at start";
}

View File

@@ -0,0 +1,9 @@
<?php
namespace Egulias\EmailValidator\Exception;
class ExpectingAT extends InvalidEmail
{
const CODE = 202;
const REASON = "Expecting AT '@' ";
}

View File

@@ -0,0 +1,9 @@
<?php
namespace Egulias\EmailValidator\Exception;
class ExpectingATEXT extends InvalidEmail
{
const CODE = 137;
const REASON = "Expecting ATEXT";
}

View File

@@ -0,0 +1,9 @@
<?php
namespace Egulias\EmailValidator\Exception;
class ExpectingCTEXT extends InvalidEmail
{
const CODE = 139;
const REASON = "Expecting CTEXT";
}

View File

@@ -0,0 +1,9 @@
<?php
namespace Egulias\EmailValidator\Exception;
class ExpectingDTEXT extends InvalidEmail
{
const CODE = 129;
const REASON = "Expected DTEXT";
}

View File

@@ -0,0 +1,9 @@
<?php
namespace Egulias\EmailValidator\Exception;
class ExpectingDomainLiteralClose extends InvalidEmail
{
const CODE = 137;
const REASON = "Closing bracket ']' for domain literal not found";
}

View File

@@ -0,0 +1,9 @@
<?php
namespace Egulias\EmailValidator\Exception;
class ExpectedQPair extends InvalidEmail
{
const CODE = 136;
const REASON = "Expecting QPAIR";
}

View File

@@ -0,0 +1,14 @@
<?php
namespace Egulias\EmailValidator\Exception;
abstract class InvalidEmail extends \InvalidArgumentException
{
const REASON = "Invalid email";
const CODE = 0;
public function __construct()
{
parent::__construct(static::REASON, static::CODE);
}
}

View File

@@ -0,0 +1,11 @@
<?php
namespace Egulias\EmailValidator\Exception;
use Egulias\EmailValidator\Exception\InvalidEmail;
class NoDNSRecord extends InvalidEmail
{
const CODE = 5;
const REASON = 'No MX or A DSN record was found for this email';
}

View File

@@ -0,0 +1,9 @@
<?php
namespace Egulias\EmailValidator\Exception;
class NoDomainPart extends InvalidEmail
{
const CODE = 131;
const REASON = "No Domain part";
}

View File

@@ -0,0 +1,9 @@
<?php
namespace Egulias\EmailValidator\Exception;
class NoLocalPart extends InvalidEmail
{
const CODE = 130;
const REASON = "No local part";
}

View File

@@ -0,0 +1,9 @@
<?php
namespace Egulias\EmailValidator\Exception;
class UnclosedComment extends InvalidEmail
{
const CODE = 146;
const REASON = "No colosing comment token found";
}

View File

@@ -0,0 +1,9 @@
<?php
namespace Egulias\EmailValidator\Exception;
class UnclosedQuotedString extends InvalidEmail
{
const CODE = 145;
const REASON = "Unclosed quoted string";
}

View File

@@ -0,0 +1,9 @@
<?php
namespace Egulias\EmailValidator\Exception;
class UnopenedComment extends InvalidEmail
{
const CODE = 152;
const REASON = "No opening comment token found";
}

View File

@@ -0,0 +1,368 @@
<?php
namespace Egulias\EmailValidator\Parser;
use Egulias\EmailValidator\EmailLexer;
use Egulias\EmailValidator\Exception\CharNotAllowed;
use Egulias\EmailValidator\Exception\CommaInDomain;
use Egulias\EmailValidator\Exception\ConsecutiveAt;
use Egulias\EmailValidator\Exception\CRLFAtTheEnd;
use Egulias\EmailValidator\Exception\CRNoLF;
use Egulias\EmailValidator\Exception\DomainHyphened;
use Egulias\EmailValidator\Exception\DotAtEnd;
use Egulias\EmailValidator\Exception\DotAtStart;
use Egulias\EmailValidator\Exception\ExpectingATEXT;
use Egulias\EmailValidator\Exception\ExpectingDomainLiteralClose;
use Egulias\EmailValidator\Exception\ExpectingDTEXT;
use Egulias\EmailValidator\Exception\NoDomainPart;
use Egulias\EmailValidator\Exception\UnopenedComment;
use Egulias\EmailValidator\Warning\AddressLiteral;
use Egulias\EmailValidator\Warning\CFWSWithFWS;
use Egulias\EmailValidator\Warning\DeprecatedComment;
use Egulias\EmailValidator\Warning\DomainLiteral;
use Egulias\EmailValidator\Warning\DomainTooLong;
use Egulias\EmailValidator\Warning\IPV6BadChar;
use Egulias\EmailValidator\Warning\IPV6ColonEnd;
use Egulias\EmailValidator\Warning\IPV6ColonStart;
use Egulias\EmailValidator\Warning\IPV6Deprecated;
use Egulias\EmailValidator\Warning\IPV6DoubleColon;
use Egulias\EmailValidator\Warning\IPV6GroupCount;
use Egulias\EmailValidator\Warning\IPV6MaxGroups;
use Egulias\EmailValidator\Warning\LabelTooLong;
use Egulias\EmailValidator\Warning\ObsoleteDTEXT;
use Egulias\EmailValidator\Warning\TLD;
class DomainPart extends Parser
{
const DOMAIN_MAX_LENGTH = 254;
protected $domainPart = '';
public function parse($domainPart)
{
$this->lexer->moveNext();
if ($this->lexer->token['type'] === EmailLexer::S_DOT) {
throw new DotAtStart();
}
if ($this->lexer->token['type'] === EmailLexer::S_EMPTY) {
throw new NoDomainPart();
}
if ($this->lexer->token['type'] === EmailLexer::S_HYPHEN) {
throw new DomainHyphened();
}
if ($this->lexer->token['type'] === EmailLexer::S_OPENPARENTHESIS) {
$this->warnings[DeprecatedComment::CODE] = new DeprecatedComment();
$this->parseDomainComments();
}
$domain = $this->doParseDomainPart();
$prev = $this->lexer->getPrevious();
$length = strlen($domain);
if ($prev['type'] === EmailLexer::S_DOT) {
throw new DotAtEnd();
}
if ($prev['type'] === EmailLexer::S_HYPHEN) {
throw new DomainHyphened();
}
if ($length > self::DOMAIN_MAX_LENGTH) {
$this->warnings[DomainTooLong::CODE] = new DomainTooLong();
}
if ($prev['type'] === EmailLexer::S_CR) {
throw new CRLFAtTheEnd();
}
$this->domainPart = $domain;
}
public function getDomainPart()
{
return $this->domainPart;
}
public function checkIPV6Tag($addressLiteral, $maxGroups = 8)
{
$prev = $this->lexer->getPrevious();
if ($prev['type'] === EmailLexer::S_COLON) {
$this->warnings[IPV6ColonEnd::CODE] = new IPV6ColonEnd();
}
$IPv6 = substr($addressLiteral, 5);
//Daniel Marschall's new IPv6 testing strategy
$matchesIP = explode(':', $IPv6);
$groupCount = count($matchesIP);
$colons = strpos($IPv6, '::');
if (count(preg_grep('/^[0-9A-Fa-f]{0,4}$/', $matchesIP, PREG_GREP_INVERT)) !== 0) {
$this->warnings[IPV6BadChar::CODE] = new IPV6BadChar();
}
if ($colons === false) {
// We need exactly the right number of groups
if ($groupCount !== $maxGroups) {
$this->warnings[IPV6GroupCount::CODE] = new IPV6GroupCount();
}
return;
}
if ($colons !== strrpos($IPv6, '::')) {
$this->warnings[IPV6DoubleColon::CODE] = new IPV6DoubleColon();
return;
}
if ($colons === 0 || $colons === (strlen($IPv6) - 2)) {
// RFC 4291 allows :: at the start or end of an address
//with 7 other groups in addition
++$maxGroups;
}
if ($groupCount > $maxGroups) {
$this->warnings[IPV6MaxGroups::CODE] = new IPV6MaxGroups();
} elseif ($groupCount === $maxGroups) {
$this->warnings[IPV6Deprecated::CODE] = new IPV6Deprecated();
}
}
protected function doParseDomainPart()
{
$domain = '';
$openedParenthesis = 0;
do {
$prev = $this->lexer->getPrevious();
$this->checkNotAllowedChars($this->lexer->token);
if ($this->lexer->token['type'] === EmailLexer::S_OPENPARENTHESIS) {
$this->parseComments();
$openedParenthesis += $this->getOpenedParenthesis();
$this->lexer->moveNext();
$tmpPrev = $this->lexer->getPrevious();
if ($tmpPrev['type'] === EmailLexer::S_CLOSEPARENTHESIS) {
$openedParenthesis--;
}
}
if ($this->lexer->token['type'] === EmailLexer::S_CLOSEPARENTHESIS) {
if ($openedParenthesis === 0) {
throw new UnopenedComment();
} else {
$openedParenthesis--;
}
}
$this->checkConsecutiveDots();
$this->checkDomainPartExceptions($prev);
if ($this->hasBrackets()) {
$this->parseDomainLiteral();
}
$this->checkLabelLength($prev);
if ($this->isFWS()) {
$this->parseFWS();
}
$domain .= $this->lexer->token['value'];
$this->lexer->moveNext();
} while ($this->lexer->token);
return $domain;
}
private function checkNotAllowedChars($token)
{
$notAllowed = [EmailLexer::S_BACKSLASH => true, EmailLexer::S_SLASH=> true];
if (isset($notAllowed[$token['type']])) {
throw new CharNotAllowed();
}
}
protected function parseDomainLiteral()
{
if ($this->lexer->isNextToken(EmailLexer::S_COLON)) {
$this->warnings[IPV6ColonStart::CODE] = new IPV6ColonStart();
}
if ($this->lexer->isNextToken(EmailLexer::S_IPV6TAG)) {
$lexer = clone $this->lexer;
$lexer->moveNext();
if ($lexer->isNextToken(EmailLexer::S_DOUBLECOLON)) {
$this->warnings[IPV6ColonStart::CODE] = new IPV6ColonStart();
}
}
return $this->doParseDomainLiteral();
}
protected function doParseDomainLiteral()
{
$IPv6TAG = false;
$addressLiteral = '';
do {
if ($this->lexer->token['type'] === EmailLexer::C_NUL) {
throw new ExpectingDTEXT();
}
if ($this->lexer->token['type'] === EmailLexer::INVALID ||
$this->lexer->token['type'] === EmailLexer::C_DEL ||
$this->lexer->token['type'] === EmailLexer::S_LF
) {
$this->warnings[ObsoleteDTEXT::CODE] = new ObsoleteDTEXT();
}
if ($this->lexer->isNextTokenAny(array(EmailLexer::S_OPENQBRACKET, EmailLexer::S_OPENBRACKET))) {
throw new ExpectingDTEXT();
}
if ($this->lexer->isNextTokenAny(
array(EmailLexer::S_HTAB, EmailLexer::S_SP, $this->lexer->token['type'] === EmailLexer::CRLF)
)) {
$this->warnings[CFWSWithFWS::CODE] = new CFWSWithFWS();
$this->parseFWS();
}
if ($this->lexer->isNextToken(EmailLexer::S_CR)) {
throw new CRNoLF();
}
if ($this->lexer->token['type'] === EmailLexer::S_BACKSLASH) {
$this->warnings[ObsoleteDTEXT::CODE] = new ObsoleteDTEXT();
$addressLiteral .= $this->lexer->token['value'];
$this->lexer->moveNext();
$this->validateQuotedPair();
}
if ($this->lexer->token['type'] === EmailLexer::S_IPV6TAG) {
$IPv6TAG = true;
}
if ($this->lexer->token['type'] === EmailLexer::S_CLOSEQBRACKET) {
break;
}
$addressLiteral .= $this->lexer->token['value'];
} while ($this->lexer->moveNext());
$addressLiteral = str_replace('[', '', $addressLiteral);
$addressLiteral = $this->checkIPV4Tag($addressLiteral);
if (false === $addressLiteral) {
return $addressLiteral;
}
if (!$IPv6TAG) {
$this->warnings[DomainLiteral::CODE] = new DomainLiteral();
return $addressLiteral;
}
$this->warnings[AddressLiteral::CODE] = new AddressLiteral();
$this->checkIPV6Tag($addressLiteral);
return $addressLiteral;
}
protected function checkIPV4Tag($addressLiteral)
{
$matchesIP = array();
// Extract IPv4 part from the end of the address-literal (if there is one)
if (preg_match(
'/\\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/',
$addressLiteral,
$matchesIP
) > 0
) {
$index = strrpos($addressLiteral, $matchesIP[0]);
if ($index === 0) {
$this->warnings[AddressLiteral::CODE] = new AddressLiteral();
return false;
}
// Convert IPv4 part to IPv6 format for further testing
$addressLiteral = substr($addressLiteral, 0, $index) . '0:0';
}
return $addressLiteral;
}
protected function checkDomainPartExceptions($prev)
{
$invalidDomainTokens = array(
EmailLexer::S_DQUOTE => true,
EmailLexer::S_SEMICOLON => true,
EmailLexer::S_GREATERTHAN => true,
EmailLexer::S_LOWERTHAN => true,
);
if (isset($invalidDomainTokens[$this->lexer->token['type']])) {
throw new ExpectingATEXT();
}
if ($this->lexer->token['type'] === EmailLexer::S_COMMA) {
throw new CommaInDomain();
}
if ($this->lexer->token['type'] === EmailLexer::S_AT) {
throw new ConsecutiveAt();
}
if ($this->lexer->token['type'] === EmailLexer::S_OPENQBRACKET && $prev['type'] !== EmailLexer::S_AT) {
throw new ExpectingATEXT();
}
if ($this->lexer->token['type'] === EmailLexer::S_HYPHEN && $this->lexer->isNextToken(EmailLexer::S_DOT)) {
throw new DomainHyphened();
}
if ($this->lexer->token['type'] === EmailLexer::S_BACKSLASH
&& $this->lexer->isNextToken(EmailLexer::GENERIC)) {
throw new ExpectingATEXT();
}
}
protected function hasBrackets()
{
if ($this->lexer->token['type'] !== EmailLexer::S_OPENBRACKET) {
return false;
}
try {
$this->lexer->find(EmailLexer::S_CLOSEBRACKET);
} catch (\RuntimeException $e) {
throw new ExpectingDomainLiteralClose();
}
return true;
}
protected function checkLabelLength($prev)
{
if ($this->lexer->token['type'] === EmailLexer::S_DOT &&
$prev['type'] === EmailLexer::GENERIC &&
strlen($prev['value']) > 63
) {
$this->warnings[LabelTooLong::CODE] = new LabelTooLong();
}
}
protected function parseDomainComments()
{
$this->isUnclosedComment();
while (!$this->lexer->isNextToken(EmailLexer::S_CLOSEPARENTHESIS)) {
$this->warnEscaping();
$this->lexer->moveNext();
}
$this->lexer->moveNext();
if ($this->lexer->isNextToken(EmailLexer::S_DOT)) {
throw new ExpectingATEXT();
}
}
protected function addTLDWarnings()
{
if ($this->warnings[DomainLiteral::CODE]) {
$this->warnings[TLD::CODE] = new TLD();
}
}
}

View File

@@ -0,0 +1,138 @@
<?php
namespace Egulias\EmailValidator\Parser;
use Egulias\EmailValidator\Exception\DotAtEnd;
use Egulias\EmailValidator\Exception\DotAtStart;
use Egulias\EmailValidator\EmailLexer;
use Egulias\EmailValidator\EmailValidator;
use Egulias\EmailValidator\Exception\ExpectingAT;
use Egulias\EmailValidator\Exception\ExpectingATEXT;
use Egulias\EmailValidator\Exception\UnclosedQuotedString;
use Egulias\EmailValidator\Exception\UnopenedComment;
use Egulias\EmailValidator\Warning\CFWSWithFWS;
use Egulias\EmailValidator\Warning\LocalTooLong;
class LocalPart extends Parser
{
public function parse($localPart)
{
$parseDQuote = true;
$closingQuote = false;
$openedParenthesis = 0;
while ($this->lexer->token['type'] !== EmailLexer::S_AT && $this->lexer->token) {
if ($this->lexer->token['type'] === EmailLexer::S_DOT && !$this->lexer->getPrevious()) {
throw new DotAtStart();
}
$closingQuote = $this->checkDQUOTE($closingQuote);
if ($closingQuote && $parseDQuote) {
$parseDQuote = $this->parseDoubleQuote();
}
if ($this->lexer->token['type'] === EmailLexer::S_OPENPARENTHESIS) {
$this->parseComments();
$openedParenthesis += $this->getOpenedParenthesis();
}
if ($this->lexer->token['type'] === EmailLexer::S_CLOSEPARENTHESIS) {
if ($openedParenthesis === 0) {
throw new UnopenedComment();
} else {
$openedParenthesis--;
}
}
$this->checkConsecutiveDots();
if ($this->lexer->token['type'] === EmailLexer::S_DOT &&
$this->lexer->isNextToken(EmailLexer::S_AT)
) {
throw new DotAtEnd();
}
$this->warnEscaping();
$this->isInvalidToken($this->lexer->token, $closingQuote);
if ($this->isFWS()) {
$this->parseFWS();
}
$this->lexer->moveNext();
}
$prev = $this->lexer->getPrevious();
if (strlen($prev['value']) > LocalTooLong::LOCAL_PART_LENGTH) {
$this->warnings[LocalTooLong::CODE] = new LocalTooLong();
}
}
protected function parseDoubleQuote()
{
$parseAgain = true;
$special = array(
EmailLexer::S_CR => true,
EmailLexer::S_HTAB => true,
EmailLexer::S_LF => true
);
$invalid = array(
EmailLexer::C_NUL => true,
EmailLexer::S_HTAB => true,
EmailLexer::S_CR => true,
EmailLexer::S_LF => true
);
$setSpecialsWarning = true;
$this->lexer->moveNext();
while ($this->lexer->token['type'] !== EmailLexer::S_DQUOTE && $this->lexer->token) {
$parseAgain = false;
if (isset($special[$this->lexer->token['type']]) && $setSpecialsWarning) {
$this->warnings[CFWSWithFWS::CODE] = new CFWSWithFWS();
$setSpecialsWarning = false;
}
if ($this->lexer->token['type'] === EmailLexer::S_BACKSLASH && $this->lexer->isNextToken(EmailLexer::S_DQUOTE)) {
$this->lexer->moveNext();
}
$this->lexer->moveNext();
if (!$this->escaped() && isset($invalid[$this->lexer->token['type']])) {
throw new ExpectingATEXT();
}
}
$prev = $this->lexer->getPrevious();
if ($prev['type'] === EmailLexer::S_BACKSLASH) {
if (!$this->checkDQUOTE(false)) {
throw new UnclosedQuotedString();
}
}
if (!$this->lexer->isNextToken(EmailLexer::S_AT) && $prev['type'] !== EmailLexer::S_BACKSLASH) {
throw new ExpectingAT();
}
return $parseAgain;
}
protected function isInvalidToken($token, $closingQuote)
{
$forbidden = array(
EmailLexer::S_COMMA,
EmailLexer::S_CLOSEBRACKET,
EmailLexer::S_OPENBRACKET,
EmailLexer::S_GREATERTHAN,
EmailLexer::S_LOWERTHAN,
EmailLexer::S_COLON,
EmailLexer::S_SEMICOLON,
EmailLexer::INVALID
);
if (in_array($token['type'], $forbidden) && !$closingQuote) {
throw new ExpectingATEXT();
}
}
}

View File

@@ -0,0 +1,215 @@
<?php
namespace Egulias\EmailValidator\Parser;
use Egulias\EmailValidator\EmailLexer;
use Egulias\EmailValidator\Exception\AtextAfterCFWS;
use Egulias\EmailValidator\Exception\ConsecutiveDot;
use Egulias\EmailValidator\Exception\CRLFAtTheEnd;
use Egulias\EmailValidator\Exception\CRLFX2;
use Egulias\EmailValidator\Exception\CRNoLF;
use Egulias\EmailValidator\Exception\ExpectedQPair;
use Egulias\EmailValidator\Exception\ExpectingATEXT;
use Egulias\EmailValidator\Exception\ExpectingCTEXT;
use Egulias\EmailValidator\Exception\UnclosedComment;
use Egulias\EmailValidator\Exception\UnclosedQuotedString;
use Egulias\EmailValidator\Warning\CFWSNearAt;
use Egulias\EmailValidator\Warning\CFWSWithFWS;
use Egulias\EmailValidator\Warning\Comment;
use Egulias\EmailValidator\Warning\QuotedPart;
use Egulias\EmailValidator\Warning\QuotedString;
abstract class Parser
{
protected $warnings = [];
protected $lexer;
protected $openedParenthesis = 0;
public function __construct(EmailLexer $lexer)
{
$this->lexer = $lexer;
}
public function getWarnings()
{
return $this->warnings;
}
abstract public function parse($str);
/** @return int */
public function getOpenedParenthesis()
{
return $this->openedParenthesis;
}
/**
* validateQuotedPair
*/
protected function validateQuotedPair()
{
if (!($this->lexer->token['type'] === EmailLexer::INVALID
|| $this->lexer->token['type'] === EmailLexer::C_DEL)) {
throw new ExpectedQPair();
}
$this->warnings[QuotedPart::CODE] =
new QuotedPart($this->lexer->getPrevious()['type'], $this->lexer->token['type']);
}
protected function parseComments()
{
$this->openedParenthesis = 1;
$this->isUnclosedComment();
$this->warnings[Comment::CODE] = new Comment();
while (!$this->lexer->isNextToken(EmailLexer::S_CLOSEPARENTHESIS)) {
if ($this->lexer->isNextToken(EmailLexer::S_OPENPARENTHESIS)) {
$this->openedParenthesis++;
}
$this->warnEscaping();
$this->lexer->moveNext();
}
$this->lexer->moveNext();
if ($this->lexer->isNextTokenAny(array(EmailLexer::GENERIC, EmailLexer::S_EMPTY))) {
throw new ExpectingATEXT();
}
if ($this->lexer->isNextToken(EmailLexer::S_AT)) {
$this->warnings[CFWSNearAt::CODE] = new CFWSNearAt();
}
}
protected function isUnclosedComment()
{
try {
$this->lexer->find(EmailLexer::S_CLOSEPARENTHESIS);
return true;
} catch (\RuntimeException $e) {
throw new UnclosedComment();
}
}
protected function parseFWS()
{
$previous = $this->lexer->getPrevious();
$this->checkCRLFInFWS();
if ($this->lexer->token['type'] === EmailLexer::S_CR) {
throw new CRNoLF();
}
if ($this->lexer->isNextToken(EmailLexer::GENERIC) && $previous['type'] !== EmailLexer::S_AT) {
throw new AtextAfterCFWS();
}
if ($this->lexer->token['type'] === EmailLexer::S_LF || $this->lexer->token['type'] === EmailLexer::C_NUL) {
throw new ExpectingCTEXT();
}
if ($this->lexer->isNextToken(EmailLexer::S_AT) || $previous['type'] === EmailLexer::S_AT) {
$this->warnings[CFWSNearAt::CODE] = new CFWSNearAt();
} else {
$this->warnings[CFWSWithFWS::CODE] = new CFWSWithFWS();
}
}
protected function checkConsecutiveDots()
{
if ($this->lexer->token['type'] === EmailLexer::S_DOT && $this->lexer->isNextToken(EmailLexer::S_DOT)) {
throw new ConsecutiveDot();
}
}
protected function isFWS()
{
if ($this->escaped()) {
return false;
}
if ($this->lexer->token['type'] === EmailLexer::S_SP ||
$this->lexer->token['type'] === EmailLexer::S_HTAB ||
$this->lexer->token['type'] === EmailLexer::S_CR ||
$this->lexer->token['type'] === EmailLexer::S_LF ||
$this->lexer->token['type'] === EmailLexer::CRLF
) {
return true;
}
return false;
}
protected function escaped()
{
$previous = $this->lexer->getPrevious();
if ($previous['type'] === EmailLexer::S_BACKSLASH
&&
$this->lexer->token['type'] !== EmailLexer::GENERIC
) {
return true;
}
return false;
}
protected function warnEscaping()
{
if ($this->lexer->token['type'] !== EmailLexer::S_BACKSLASH) {
return false;
}
if ($this->lexer->isNextToken(EmailLexer::GENERIC)) {
throw new ExpectingATEXT();
}
if (!$this->lexer->isNextTokenAny(array(EmailLexer::S_SP, EmailLexer::S_HTAB, EmailLexer::C_DEL))) {
return false;
}
$this->warnings[QuotedPart::CODE] =
new QuotedPart($this->lexer->getPrevious()['type'], $this->lexer->token['type']);
return true;
}
protected function checkDQUOTE($hasClosingQuote)
{
if ($this->lexer->token['type'] !== EmailLexer::S_DQUOTE) {
return $hasClosingQuote;
}
if ($hasClosingQuote) {
return $hasClosingQuote;
}
$previous = $this->lexer->getPrevious();
if ($this->lexer->isNextToken(EmailLexer::GENERIC) && $previous['type'] === EmailLexer::GENERIC) {
throw new ExpectingATEXT();
}
try {
$this->lexer->find(EmailLexer::S_DQUOTE);
$hasClosingQuote = true;
} catch (\Exception $e) {
throw new UnclosedQuotedString();
}
$this->warnings[QuotedString::CODE] = new QuotedString($previous['value'], $this->lexer->token['value']);
return $hasClosingQuote;
}
protected function checkCRLFInFWS()
{
if ($this->lexer->token['type'] !== EmailLexer::CRLF) {
return;
}
if (!$this->lexer->isNextTokenAny(array(EmailLexer::S_SP, EmailLexer::S_HTAB))) {
throw new CRLFX2();
}
if (!$this->lexer->isNextTokenAny(array(EmailLexer::S_SP, EmailLexer::S_HTAB))) {
throw new CRLFAtTheEnd();
}
}
}

View File

@@ -0,0 +1,61 @@
<?php
namespace Egulias\EmailValidator\Validation;
use Egulias\EmailValidator\EmailLexer;
use Egulias\EmailValidator\Exception\InvalidEmail;
use Egulias\EmailValidator\Warning\NoDNSMXRecord;
use Egulias\EmailValidator\Exception\NoDNSRecord;
class DNSCheckValidation implements EmailValidation
{
/**
* @var array
*/
private $warnings = [];
/**
* @var InvalidEmail
*/
private $error;
public function isValid($email, EmailLexer $emailLexer)
{
// use the input to check DNS if we cannot extract something similar to a domain
$host = $email;
// Arguable pattern to extract the domain. Not aiming to validate the domain nor the email
if (false !== $lastAtPos = strrpos($email, '@')) {
$host = substr($email, $lastAtPos + 1);
}
return $this->checkDNS($host);
}
public function getError()
{
return $this->error;
}
public function getWarnings()
{
return $this->warnings;
}
protected function checkDNS($host)
{
$host = rtrim($host, '.') . '.';
$Aresult = true;
$MXresult = checkdnsrr($host, 'MX');
if (!$MXresult) {
$this->warnings[NoDNSMXRecord::CODE] = new NoDNSMXRecord();
$Aresult = checkdnsrr($host, 'A') || checkdnsrr($host, 'AAAA');
if (!$Aresult) {
$this->error = new NoDNSRecord();
}
}
return $MXresult || $Aresult;
}
}

View File

@@ -0,0 +1,34 @@
<?php
namespace Egulias\EmailValidator\Validation;
use Egulias\EmailValidator\EmailLexer;
use Egulias\EmailValidator\Exception\InvalidEmail;
use Egulias\EmailValidator\Warning\Warning;
interface EmailValidation
{
/**
* Returns true if the given email is valid.
*
* @param string $email The email you want to validate.
* @param EmailLexer $emailLexer The email lexer.
*
* @return bool
*/
public function isValid($email, EmailLexer $emailLexer);
/**
* Returns the validation error.
*
* @return InvalidEmail|null
*/
public function getError();
/**
* Returns the validation warnings.
*
* @return Warning[]
*/
public function getWarnings();
}

View File

@@ -0,0 +1,11 @@
<?php
namespace Egulias\EmailValidator\Validation\Error;
use Egulias\EmailValidator\Exception\InvalidEmail;
class RFCWarnings extends InvalidEmail
{
const CODE = 997;
const REASON = 'Warnings were found.';
}

View File

@@ -0,0 +1,11 @@
<?php
namespace Egulias\EmailValidator\Validation\Error;
use Egulias\EmailValidator\Exception\InvalidEmail;
class SpoofEmail extends InvalidEmail
{
const CODE = 998;
const REASON = "The email contains mixed UTF8 chars that makes it suspicious";
}

View File

@@ -0,0 +1,13 @@
<?php
namespace Egulias\EmailValidator\Validation\Exception;
use Exception;
class EmptyValidationList extends \InvalidArgumentException
{
public function __construct($code = 0, Exception $previous = null)
{
parent::__construct("Empty validation list is not allowed", $code, $previous);
}
}

View File

@@ -0,0 +1,26 @@
<?php
namespace Egulias\EmailValidator\Validation;
use Egulias\EmailValidator\Exception\InvalidEmail;
class MultipleErrors extends InvalidEmail
{
const CODE = 999;
const REASON = "Accumulated errors for multiple validations";
/**
* @var array
*/
private $errors = [];
public function __construct(array $errors)
{
$this->errors = $errors;
parent::__construct();
}
public function getErrors()
{
return $this->errors;
}
}

View File

@@ -0,0 +1,110 @@
<?php
namespace Egulias\EmailValidator\Validation;
use Egulias\EmailValidator\EmailLexer;
use Egulias\EmailValidator\Validation\Exception\EmptyValidationList;
class MultipleValidationWithAnd implements EmailValidation
{
/**
* If one of validations gets failure skips all succeeding validation.
* This means MultipleErrors will only contain a single error which first found.
*/
const STOP_ON_ERROR = 0;
/**
* All of validations will be invoked even if one of them got failure.
* So MultipleErrors will contain all causes.
*/
const ALLOW_ALL_ERRORS = 1;
/**
* @var EmailValidation[]
*/
private $validations = [];
/**
* @var array
*/
private $warnings = [];
/**
* @var MultipleErrors
*/
private $error;
/**
* @var bool
*/
private $mode;
/**
* @param EmailValidation[] $validations The validations.
* @param int $mode The validation mode (one of the constants).
*/
public function __construct(array $validations, $mode = self::ALLOW_ALL_ERRORS)
{
if (count($validations) == 0) {
throw new EmptyValidationList();
}
$this->validations = $validations;
$this->mode = $mode;
}
/**
* {@inheritdoc}
*/
public function isValid($email, EmailLexer $emailLexer)
{
$result = true;
$errors = [];
foreach ($this->validations as $validation) {
$emailLexer->reset();
$result = $result && $validation->isValid($email, $emailLexer);
$this->warnings = array_merge($this->warnings, $validation->getWarnings());
$errors = $this->addNewError($validation->getError(), $errors);
if ($this->shouldStop($result)) {
break;
}
}
if (!empty($errors)) {
$this->error = new MultipleErrors($errors);
}
return $result;
}
private function addNewError($possibleError, array $errors)
{
if (null !== $possibleError) {
$errors[] = $possibleError;
}
return $errors;
}
private function shouldStop($result)
{
return !$result && $this->mode === self::STOP_ON_ERROR;
}
/**
* {@inheritdoc}
*/
public function getError()
{
return $this->error;
}
/**
* {@inheritdoc}
*/
public function getWarnings()
{
return $this->warnings;
}
}

View File

@@ -0,0 +1,41 @@
<?php
namespace Egulias\EmailValidator\Validation;
use Egulias\EmailValidator\EmailLexer;
use Egulias\EmailValidator\Exception\InvalidEmail;
use Egulias\EmailValidator\Validation\Error\RFCWarnings;
class NoRFCWarningsValidation extends RFCValidation
{
/**
* @var InvalidEmail
*/
private $error;
/**
* {@inheritdoc}
*/
public function isValid($email, EmailLexer $emailLexer)
{
if (!parent::isValid($email, $emailLexer)) {
return false;
}
if (empty($this->getWarnings())) {
return true;
}
$this->error = new RFCWarnings();
return false;
}
/**
* {@inheritdoc}
*/
public function getError()
{
return $this->error ?: parent::getError();
}
}

View File

@@ -0,0 +1,49 @@
<?php
namespace Egulias\EmailValidator\Validation;
use Egulias\EmailValidator\EmailLexer;
use Egulias\EmailValidator\EmailParser;
use Egulias\EmailValidator\Exception\InvalidEmail;
class RFCValidation implements EmailValidation
{
/**
* @var EmailParser
*/
private $parser;
/**
* @var array
*/
private $warnings = [];
/**
* @var InvalidEmail
*/
private $error;
public function isValid($email, EmailLexer $emailLexer)
{
$this->parser = new EmailParser($emailLexer);
try {
$this->parser->parse((string)$email);
} catch (InvalidEmail $invalid) {
$this->error = $invalid;
return false;
}
$this->warnings = $this->parser->getWarnings();
return true;
}
public function getError()
{
return $this->error;
}
public function getWarnings()
{
return $this->warnings;
}
}

View File

@@ -0,0 +1,45 @@
<?php
namespace Egulias\EmailValidator\Validation;
use Egulias\EmailValidator\EmailLexer;
use Egulias\EmailValidator\Exception\InvalidEmail;
use Egulias\EmailValidator\Validation\Error\SpoofEmail;
use \Spoofchecker;
class SpoofCheckValidation implements EmailValidation
{
/**
* @var InvalidEmail
*/
private $error;
public function __construct()
{
if (!class_exists(Spoofchecker::class)) {
throw new \LogicException(sprintf('The %s class requires the Intl extension.', __CLASS__));
}
}
public function isValid($email, EmailLexer $emailLexer)
{
$checker = new Spoofchecker();
$checker->setChecks(Spoofchecker::SINGLE_SCRIPT);
if ($checker->isSuspicious($email)) {
$this->error = new SpoofEmail();
}
return $this->error === null;
}
public function getError()
{
return $this->error;
}
public function getWarnings()
{
return [];
}
}

View File

@@ -0,0 +1,14 @@
<?php
namespace Egulias\EmailValidator\Warning;
class AddressLiteral extends Warning
{
const CODE = 12;
public function __construct()
{
$this->message = 'Address literal in domain part';
$this->rfcNumber = 5321;
}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace Egulias\EmailValidator\Warning;
class CFWSNearAt extends Warning
{
const CODE = 49;
public function __construct()
{
$this->message = "Deprecated folding white space near @";
}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace Egulias\EmailValidator\Warning;
class CFWSWithFWS extends Warning
{
const CODE = 18;
public function __construct()
{
$this->message = 'Folding whites space followed by folding white space';
}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace Egulias\EmailValidator\Warning;
class Comment extends Warning
{
const CODE = 17;
public function __construct()
{
$this->message = "Comments found in this email";
}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace Egulias\EmailValidator\Warning;
class DeprecatedComment extends Warning
{
const CODE = 37;
public function __construct()
{
$this->message = 'Deprecated comments';
}
}

View File

@@ -0,0 +1,14 @@
<?php
namespace Egulias\EmailValidator\Warning;
class DomainLiteral extends Warning
{
const CODE = 70;
public function __construct()
{
$this->message = 'Domain Literal';
$this->rfcNumber = 5322;
}
}

View File

@@ -0,0 +1,14 @@
<?php
namespace Egulias\EmailValidator\Warning;
class DomainTooLong extends Warning
{
const CODE = 255;
public function __construct()
{
$this->message = 'Domain is too long, exceeds 255 chars';
$this->rfcNumber = 5322;
}
}

View File

@@ -0,0 +1,15 @@
<?php
namespace Egulias\EmailValidator\Warning;
use Egulias\EmailValidator\EmailParser;
class EmailTooLong extends Warning
{
const CODE = 66;
public function __construct()
{
$this->message = 'Email is too long, exceeds ' . EmailParser::EMAIL_MAX_LENGTH;
}
}

View File

@@ -0,0 +1,14 @@
<?php
namespace Egulias\EmailValidator\Warning;
class IPV6BadChar extends Warning
{
const CODE = 74;
public function __construct()
{
$this->message = 'Bad char in IPV6 domain literal';
$this->rfcNumber = 5322;
}
}

View File

@@ -0,0 +1,14 @@
<?php
namespace Egulias\EmailValidator\Warning;
class IPV6ColonEnd extends Warning
{
const CODE = 77;
public function __construct()
{
$this->message = ':: found at the end of the domain literal';
$this->rfcNumber = 5322;
}
}

View File

@@ -0,0 +1,14 @@
<?php
namespace Egulias\EmailValidator\Warning;
class IPV6ColonStart extends Warning
{
const CODE = 76;
public function __construct()
{
$this->message = ':: found at the start of the domain literal';
$this->rfcNumber = 5322;
}
}

View File

@@ -0,0 +1,14 @@
<?php
namespace Egulias\EmailValidator\Warning;
class IPV6Deprecated extends Warning
{
const CODE = 13;
public function __construct()
{
$this->message = 'Deprecated form of IPV6';
$this->rfcNumber = 5321;
}
}

View File

@@ -0,0 +1,14 @@
<?php
namespace Egulias\EmailValidator\Warning;
class IPV6DoubleColon extends Warning
{
const CODE = 73;
public function __construct()
{
$this->message = 'Double colon found after IPV6 tag';
$this->rfcNumber = 5322;
}
}

View File

@@ -0,0 +1,14 @@
<?php
namespace Egulias\EmailValidator\Warning;
class IPV6GroupCount extends Warning
{
const CODE = 72;
public function __construct()
{
$this->message = 'Group count is not IPV6 valid';
$this->rfcNumber = 5322;
}
}

View File

@@ -0,0 +1,14 @@
<?php
namespace Egulias\EmailValidator\Warning;
class IPV6MaxGroups extends Warning
{
const CODE = 75;
public function __construct()
{
$this->message = 'Reached the maximum number of IPV6 groups allowed';
$this->rfcNumber = 5321;
}
}

View File

@@ -0,0 +1,14 @@
<?php
namespace Egulias\EmailValidator\Warning;
class LabelTooLong extends Warning
{
const CODE = 63;
public function __construct()
{
$this->message = 'Label too long';
$this->rfcNumber = 5322;
}
}

View File

@@ -0,0 +1,15 @@
<?php
namespace Egulias\EmailValidator\Warning;
class LocalTooLong extends Warning
{
const CODE = 64;
const LOCAL_PART_LENGTH = 64;
public function __construct()
{
$this->message = 'Local part is too long, exceeds 64 chars (octets)';
$this->rfcNumber = 5322;
}
}

View File

@@ -0,0 +1,14 @@
<?php
namespace Egulias\EmailValidator\Warning;
class NoDNSMXRecord extends Warning
{
const CODE = 6;
public function __construct()
{
$this->message = 'No MX DSN record was found for this email';
$this->rfcNumber = 5321;
}
}

View File

@@ -0,0 +1,14 @@
<?php
namespace Egulias\EmailValidator\Warning;
class ObsoleteDTEXT extends Warning
{
const CODE = 71;
public function __construct()
{
$this->rfcNumber = 5322;
$this->message = 'Obsolete DTEXT in domain literal';
}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace Egulias\EmailValidator\Warning;
class QuotedPart extends Warning
{
const CODE = 36;
public function __construct($prevToken, $postToken)
{
$this->message = "Deprecated Quoted String found between $prevToken and $postToken";
}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace Egulias\EmailValidator\Warning;
class QuotedString extends Warning
{
const CODE = 11;
public function __construct($prevToken, $postToken)
{
$this->message = "Quoted String found between $prevToken and $postToken";
}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace Egulias\EmailValidator\Warning;
class TLD extends Warning
{
const CODE = 9;
public function __construct()
{
$this->message = "RFC5321, TLD";
}
}

View File

@@ -0,0 +1,30 @@
<?php
namespace Egulias\EmailValidator\Warning;
abstract class Warning
{
const CODE = 0;
protected $message;
protected $rfcNumber;
public function message()
{
return $this->message;
}
public function code()
{
return self::CODE;
}
public function RFCNumber()
{
return $this->rfcNumber;
}
public function __toString()
{
return $this->message() . " rfc: " . $this->rfcNumber . "interal code: " . static::CODE;
}
}

View File

@@ -0,0 +1,19 @@
Copyright (c) 2013-2016 Eduardo Gulias Davis
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -0,0 +1,79 @@
# EmailValidator
[![Build Status](https://travis-ci.org/egulias/EmailValidator.png?branch=master)](https://travis-ci.org/egulias/EmailValidator) [![Coverage Status](https://coveralls.io/repos/egulias/EmailValidator/badge.png?branch=master)](https://coveralls.io/r/egulias/EmailValidator?branch=master) [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/egulias/EmailValidator/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/egulias/EmailValidator/?branch=master) [![SensioLabsInsight](https://insight.sensiolabs.com/projects/22ba6692-9c02-42e5-a65d-1c5696bfffc6/small.png)](https://insight.sensiolabs.com/projects/22ba6692-9c02-42e5-a65d-1c5696bfffc6)
=============================
With the help of [PHPStorm](https://www.jetbrains.com/phpstorm/)
## Requirements ##
* [Composer](https://getcomposer.org) is required for installation
* [Spoofchecking](https://github.com/egulias/EmailValidator/blob/master/EmailValidator/Validation/SpoofCheckValidation.php) validation requires that your PHP system have the [PHP Internationalization Libraries](http://php.net/manual/en/book.intl.php) (also known as PHP Intl)
## Installation ##
Run the command below to install via Composer
```shell
composer require egulias/email-validator "~2.1"
```
## Getting Started ##
`EmailValidator`requires you to decide which (or combination of them) validation/s strategy/ies you'd like to follow for each [validation](#available-validations).
A basic example with the RFC validation
```php
<?php
use Egulias\EmailValidator\EmailValidator;
use Egulias\EmailValidator\Validation\RFCValidation;
$validator = new EmailValidator();
$validator->isValid("example@example.com", new RFCValidation()); //true
```
### Available validations ###
1. [RFCValidation](https://github.com/egulias/EmailValidator/blob/master/EmailValidator/Validation/RFCValidation.php)
2. [NoRFCWarningsValidation](https://github.com/egulias/EmailValidator/blob/master/EmailValidator/Validation/NoRFCWarningsValidation.php)
3. [DNSCheckValidation](https://github.com/egulias/EmailValidator/blob/master/EmailValidator/Validation/DNSCheckValidation.php)
4. [SpoofCheckValidation](https://github.com/egulias/EmailValidator/blob/master/EmailValidator/Validation/SpoofCheckValidation.php)
5. [MultipleValidationWithAnd](https://github.com/egulias/EmailValidator/blob/master/EmailValidator/Validation/MultipleValidationWithAnd.php)
6. [Your own validation](#how-to-extend)
`MultipleValidationWithAnd`
It is a validation that operates over other validations performing a logical and (&&) over the result of each validation.
```php
<?php
use Egulias\EmailValidator\EmailValidator;
use Egulias\EmailValidator\Validation\DNSCheckValidation;
use Egulias\EmailValidator\Validation\MultipleValidationWithAnd;
use Egulias\EmailValidator\Validation\RFCValidation;
$validator = new EmailValidator();
$multipleValidations = new MultipleValidationWithAnd([
new RFCValidation(),
new DNSCheckValidation()
]);
$validator->isValid("example@example.com", $multipleValidations); //true
```
### How to extend ###
It's easy! You just need to extend [EmailValidation](https://github.com/egulias/EmailValidator/blob/master/EmailValidator/Validation/EmailValidation.php) and you can use your own validation.
## Other Contributors ##
(You can find current contributors [here](https://github.com/egulias/EmailValidator/graphs/contributors))
As this is a port from another library and work, here are other people related to the previous one:
* Ricard Clau [@ricardclau](http://github.com/ricardclau): Performance against PHP built-in filter_var
* Josepf Bielawski [@stloyd](http://github.com/stloyd): For its first re-work of Dominic's lib
* Dominic Sayers [@dominicsayers](http://github.com/dominicsayers): The original isemail function
## License ##
Released under the MIT License attached with this code.

View File

@@ -0,0 +1,39 @@
{
"name": "egulias/email-validator",
"description": "A library for validating emails against several RFCs",
"homepage": "https://github.com/egulias/EmailValidator",
"type": "Library",
"keywords": ["email", "validation", "validator", "emailvalidation", "emailvalidator"],
"license": "MIT",
"authors": [
{"name": "Eduardo Gulias Davis"}
],
"extra": {
"branch-alias": {
"dev-master": "2.0.x-dev"
}
},
"repositories": [
{
"type": "git",
"url": "https://github.com/dominicsayers/isemail"
}
],
"require": {
"php": ">= 5.5",
"doctrine/lexer": "^1.0.1"
},
"require-dev" : {
"satooshi/php-coveralls": "^1.0.1",
"phpunit/phpunit": "^4.8.35",
"dominicsayers/isemail": "dev-master"
},
"suggest": {
"ext-intl": "PHP Internationalization Libraries are required to use the SpoofChecking validation"
},
"autoload": {
"psr-4": {
"Egulias\\EmailValidator\\": "EmailValidator"
}
}
}

1813
lib/composer/vendor/egulias/email-validator/composer.lock generated vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
backupStaticAttributes="false"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
syntaxCheck="false"
bootstrap="vendor/autoload.php"
>
<testsuites>
<testsuite name="EmailValidator Test Suite">
<directory>./Tests/EmailValidator</directory>
<exclude>./vendor/</exclude>
</testsuite>
</testsuites>
<filter>
<blacklist>
<directory>./vendor</directory>
</blacklist>
</filter>
</phpunit>

Some files were not shown because too many files have changed in this diff Show More