├── .gitattributes ├── .gitignore ├── README.md ├── bootstrap.css ├── bootstrap.min.css ├── bootstrap.min.js ├── contact.php ├── helpers └── security.php ├── index.php ├── jquery-3.1.1.min.js ├── libs ├── PHPMailerAutoload.php ├── class.phpmailer.php ├── class.pop3.php ├── class.smtp.php └── phpmailer │ ├── PHPMailerAutoload.php │ ├── class.phpmailer.php │ ├── class.pop3.php │ └── class.smtp.php └── thanks.php /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # Windows shortcuts 18 | *.lnk 19 | 20 | # ========================= 21 | # Operating System Files 22 | # ========================= 23 | 24 | # OSX 25 | # ========================= 26 | 27 | .DS_Store 28 | .AppleDouble 29 | .LSOverride 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear in the root of a volume 35 | .DocumentRevisions-V100 36 | .fseventsd 37 | .Spotlight-V100 38 | .TemporaryItems 39 | .Trashes 40 | .VolumeIcon.icns 41 | 42 | # Directories potentially created on remote AFP share 43 | .AppleDB 44 | .AppleDesktop 45 | Network Trash Folder 46 | Temporary Items 47 | .apdisk 48 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Contact-Form-PHP 2 | Working Contact Form in PHP. Please note you need to implement changes in contact.php ie place your email address and password. 3 | 4 | This contact form has basic security features which you can choose to extend upon. 5 | 6 | Built using tutorials, and other resources. 7 | Thanks 8 | -------------------------------------------------------------------------------- /bootstrap.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v4.0.0-alpha.5 (https://getbootstrap.com) 3 | * Copyright 2011-2016 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) 4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 5 | */ 6 | if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){var b=a.fn.jquery.split(" ")[0].split(".");if(b[0]<2&&b[1]<9||1==b[0]&&9==b[1]&&b[2]<1||b[0]>=4)throw new Error("Bootstrap's JavaScript requires at least jQuery v1.9.1 but less than v4.0.0")}(jQuery),+function(){function a(a,b){if(!a)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!b||"object"!=typeof b&&"function"!=typeof b?a:b}function b(a,b){if("function"!=typeof b&&null!==b)throw new TypeError("Super expression must either be null or a function, not "+typeof b);a.prototype=Object.create(b&&b.prototype,{constructor:{value:a,enumerable:!1,writable:!0,configurable:!0}}),b&&(Object.setPrototypeOf?Object.setPrototypeOf(a,b):a.__proto__=b)}function c(a,b){if(!(a instanceof b))throw new TypeError("Cannot call a class as a function")}var d="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(a){return typeof a}:function(a){return a&&"function"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?"symbol":typeof a},e=function(){function a(a,b){for(var c=0;cthis._items.length-1||b<0)){if(this._isSliding)return void a(this._element).one(r.SLID,function(){return c.to(b)});if(d===b)return this.pause(),void this.cycle();var e=b>d?q.NEXT:q.PREVIOUS;this._slide(e,this._items[b])}},j.prototype.dispose=function(){a(this._element).off(i),a.removeData(this._element,h),this._items=null,this._config=null,this._element=null,this._interval=null,this._isPaused=null,this._isSliding=null,this._activeElement=null,this._indicatorsElement=null},j.prototype._getConfig=function(c){return c=a.extend({},o,c),f.typeCheckConfig(b,c,p),c},j.prototype._addEventListeners=function(){this._config.keyboard&&a(this._element).on(r.KEYDOWN,a.proxy(this._keydown,this)),"hover"!==this._config.pause||"ontouchstart"in document.documentElement||a(this._element).on(r.MOUSEENTER,a.proxy(this.pause,this)).on(r.MOUSELEAVE,a.proxy(this.cycle,this))},j.prototype._keydown=function(a){if(a.preventDefault(),!/input|textarea/i.test(a.target.tagName))switch(a.which){case m:this.prev();break;case n:this.next();break;default:return}},j.prototype._getItemIndex=function(b){return this._items=a.makeArray(a(b).parent().find(t.ITEM)),this._items.indexOf(b)},j.prototype._getItemByDirection=function(a,b){var c=a===q.NEXT,d=a===q.PREVIOUS,e=this._getItemIndex(b),f=this._items.length-1,g=d&&0===e||c&&e===f;if(g&&!this._config.wrap)return b;var h=a===q.PREVIOUS?-1:1,i=(e+h)%this._items.length;return i===-1?this._items[this._items.length-1]:this._items[i]},j.prototype._triggerSlideEvent=function(b,c){var d=a.Event(r.SLIDE,{relatedTarget:b,direction:c});return a(this._element).trigger(d),d},j.prototype._setActiveIndicatorElement=function(b){if(this._indicatorsElement){a(this._indicatorsElement).find(t.ACTIVE).removeClass(s.ACTIVE);var c=this._indicatorsElement.children[this._getItemIndex(b)];c&&a(c).addClass(s.ACTIVE)}},j.prototype._slide=function(b,c){var d=this,e=a(this._element).find(t.ACTIVE_ITEM)[0],g=c||e&&this._getItemByDirection(b,e),h=Boolean(this._interval),i=b===q.NEXT?s.LEFT:s.RIGHT;if(g&&a(g).hasClass(s.ACTIVE))return void(this._isSliding=!1);var j=this._triggerSlideEvent(g,i);if(!j.isDefaultPrevented()&&e&&g){this._isSliding=!0,h&&this.pause(),this._setActiveIndicatorElement(g);var k=a.Event(r.SLID,{relatedTarget:g,direction:i});f.supportsTransitionEnd()&&a(this._element).hasClass(s.SLIDE)?(a(g).addClass(b),f.reflow(g),a(e).addClass(i),a(g).addClass(i),a(e).one(f.TRANSITION_END,function(){a(g).removeClass(i).removeClass(b),a(g).addClass(s.ACTIVE),a(e).removeClass(s.ACTIVE).removeClass(b).removeClass(i),d._isSliding=!1,setTimeout(function(){return a(d._element).trigger(k)},0)}).emulateTransitionEnd(l)):(a(e).removeClass(s.ACTIVE),a(g).addClass(s.ACTIVE),this._isSliding=!1,a(this._element).trigger(k)),h&&this.cycle()}},j._jQueryInterface=function(b){return this.each(function(){var c=a(this).data(h),e=a.extend({},o,a(this).data());"object"===("undefined"==typeof b?"undefined":d(b))&&a.extend(e,b);var f="string"==typeof b?b:e.slide;if(c||(c=new j(this,e),a(this).data(h,c)),"number"==typeof b)c.to(b);else if("string"==typeof f){if(void 0===c[f])throw new Error('No method named "'+f+'"');c[f]()}else e.interval&&(c.pause(),c.cycle())})},j._dataApiClickHandler=function(b){var c=f.getSelectorFromElement(this);if(c){var d=a(c)[0];if(d&&a(d).hasClass(s.CAROUSEL)){var e=a.extend({},a(d).data(),a(this).data()),g=this.getAttribute("data-slide-to");g&&(e.interval=!1),j._jQueryInterface.call(a(d),e),g&&a(d).data(h).to(g),b.preventDefault()}}},e(j,null,[{key:"VERSION",get:function(){return g}},{key:"Default",get:function(){return o}}]),j}();return a(document).on(r.CLICK_DATA_API,t.DATA_SLIDE,u._dataApiClickHandler),a(window).on(r.LOAD_DATA_API,function(){a(t.DATA_RIDE).each(function(){var b=a(this);u._jQueryInterface.call(b,b.data())})}),a.fn[b]=u._jQueryInterface,a.fn[b].Constructor=u,a.fn[b].noConflict=function(){return a.fn[b]=k,u._jQueryInterface},u}(jQuery),function(a){var b="collapse",g="4.0.0-alpha.5",h="bs.collapse",i="."+h,j=".data-api",k=a.fn[b],l=600,m={toggle:!0,parent:""},n={toggle:"boolean",parent:"string"},o={SHOW:"show"+i,SHOWN:"shown"+i,HIDE:"hide"+i,HIDDEN:"hidden"+i,CLICK_DATA_API:"click"+i+j},p={IN:"in",COLLAPSE:"collapse",COLLAPSING:"collapsing",COLLAPSED:"collapsed"},q={WIDTH:"width",HEIGHT:"height"},r={ACTIVES:".card > .in, .card > .collapsing",DATA_TOGGLE:'[data-toggle="collapse"]'},s=function(){function i(b,d){c(this,i),this._isTransitioning=!1,this._element=b,this._config=this._getConfig(d),this._triggerArray=a.makeArray(a('[data-toggle="collapse"][href="#'+b.id+'"],'+('[data-toggle="collapse"][data-target="#'+b.id+'"]'))),this._parent=this._config.parent?this._getParent():null,this._config.parent||this._addAriaAndCollapsedClass(this._element,this._triggerArray),this._config.toggle&&this.toggle()}return i.prototype.toggle=function(){a(this._element).hasClass(p.IN)?this.hide():this.show()},i.prototype.show=function(){var b=this;if(!this._isTransitioning&&!a(this._element).hasClass(p.IN)){var c=void 0,d=void 0;if(this._parent&&(c=a.makeArray(a(r.ACTIVES)),c.length||(c=null)),!(c&&(d=a(c).data(h),d&&d._isTransitioning))){var e=a.Event(o.SHOW);if(a(this._element).trigger(e),!e.isDefaultPrevented()){c&&(i._jQueryInterface.call(a(c),"hide"),d||a(c).data(h,null));var g=this._getDimension();a(this._element).removeClass(p.COLLAPSE).addClass(p.COLLAPSING),this._element.style[g]=0,this._element.setAttribute("aria-expanded",!0),this._triggerArray.length&&a(this._triggerArray).removeClass(p.COLLAPSED).attr("aria-expanded",!0),this.setTransitioning(!0);var j=function(){a(b._element).removeClass(p.COLLAPSING).addClass(p.COLLAPSE).addClass(p.IN),b._element.style[g]="",b.setTransitioning(!1),a(b._element).trigger(o.SHOWN)};if(!f.supportsTransitionEnd())return void j();var k=g[0].toUpperCase()+g.slice(1),m="scroll"+k;a(this._element).one(f.TRANSITION_END,j).emulateTransitionEnd(l),this._element.style[g]=this._element[m]+"px"}}}},i.prototype.hide=function(){var b=this;if(!this._isTransitioning&&a(this._element).hasClass(p.IN)){var c=a.Event(o.HIDE);if(a(this._element).trigger(c),!c.isDefaultPrevented()){var d=this._getDimension(),e=d===q.WIDTH?"offsetWidth":"offsetHeight";this._element.style[d]=this._element[e]+"px",f.reflow(this._element),a(this._element).addClass(p.COLLAPSING).removeClass(p.COLLAPSE).removeClass(p.IN),this._element.setAttribute("aria-expanded",!1),this._triggerArray.length&&a(this._triggerArray).addClass(p.COLLAPSED).attr("aria-expanded",!1),this.setTransitioning(!0);var g=function(){b.setTransitioning(!1),a(b._element).removeClass(p.COLLAPSING).addClass(p.COLLAPSE).trigger(o.HIDDEN)};return this._element.style[d]="",f.supportsTransitionEnd()?void a(this._element).one(f.TRANSITION_END,g).emulateTransitionEnd(l):void g()}}},i.prototype.setTransitioning=function(a){this._isTransitioning=a},i.prototype.dispose=function(){a.removeData(this._element,h),this._config=null,this._parent=null,this._element=null,this._triggerArray=null,this._isTransitioning=null},i.prototype._getConfig=function(c){return c=a.extend({},m,c),c.toggle=Boolean(c.toggle),f.typeCheckConfig(b,c,n),c},i.prototype._getDimension=function(){var b=a(this._element).hasClass(q.WIDTH);return b?q.WIDTH:q.HEIGHT},i.prototype._getParent=function(){var b=this,c=a(this._config.parent)[0],d='[data-toggle="collapse"][data-parent="'+this._config.parent+'"]';return a(c).find(d).each(function(a,c){b._addAriaAndCollapsedClass(i._getTargetFromElement(c),[c])}),c},i.prototype._addAriaAndCollapsedClass=function(b,c){if(b){var d=a(b).hasClass(p.IN);b.setAttribute("aria-expanded",d),c.length&&a(c).toggleClass(p.COLLAPSED,!d).attr("aria-expanded",d)}},i._getTargetFromElement=function(b){var c=f.getSelectorFromElement(b);return c?a(c)[0]:null},i._jQueryInterface=function(b){return this.each(function(){var c=a(this),e=c.data(h),f=a.extend({},m,c.data(),"object"===("undefined"==typeof b?"undefined":d(b))&&b);if(!e&&f.toggle&&/show|hide/.test(b)&&(f.toggle=!1),e||(e=new i(this,f),c.data(h,e)),"string"==typeof b){if(void 0===e[b])throw new Error('No method named "'+b+'"');e[b]()}})},e(i,null,[{key:"VERSION",get:function(){return g}},{key:"Default",get:function(){return m}}]),i}();return a(document).on(o.CLICK_DATA_API,r.DATA_TOGGLE,function(b){b.preventDefault();var c=s._getTargetFromElement(this),d=a(c).data(h),e=d?"toggle":a(this).data();s._jQueryInterface.call(a(c),e)}),a.fn[b]=s._jQueryInterface,a.fn[b].Constructor=s,a.fn[b].noConflict=function(){return a.fn[b]=k,s._jQueryInterface},s}(jQuery),function(a){var b="dropdown",d="4.0.0-alpha.5",g="bs.dropdown",h="."+g,i=".data-api",j=a.fn[b],k=27,l=38,m=40,n=3,o={HIDE:"hide"+h,HIDDEN:"hidden"+h,SHOW:"show"+h,SHOWN:"shown"+h,CLICK:"click"+h,CLICK_DATA_API:"click"+h+i,KEYDOWN_DATA_API:"keydown"+h+i},p={BACKDROP:"dropdown-backdrop",DISABLED:"disabled",OPEN:"open"},q={BACKDROP:".dropdown-backdrop",DATA_TOGGLE:'[data-toggle="dropdown"]',FORM_CHILD:".dropdown form",ROLE_MENU:'[role="menu"]',ROLE_LISTBOX:'[role="listbox"]',NAVBAR_NAV:".navbar-nav",VISIBLE_ITEMS:'[role="menu"] li:not(.disabled) a, [role="listbox"] li:not(.disabled) a'},r=function(){function b(a){c(this,b),this._element=a,this._addEventListeners()}return b.prototype.toggle=function(){if(this.disabled||a(this).hasClass(p.DISABLED))return!1;var c=b._getParentFromElement(this),d=a(c).hasClass(p.OPEN);if(b._clearMenus(),d)return!1;if("ontouchstart"in document.documentElement&&!a(c).closest(q.NAVBAR_NAV).length){var e=document.createElement("div");e.className=p.BACKDROP,a(e).insertBefore(this),a(e).on("click",b._clearMenus)}var f={relatedTarget:this},g=a.Event(o.SHOW,f);return a(c).trigger(g),!g.isDefaultPrevented()&&(this.focus(),this.setAttribute("aria-expanded","true"),a(c).toggleClass(p.OPEN),a(c).trigger(a.Event(o.SHOWN,f)),!1)},b.prototype.dispose=function(){a.removeData(this._element,g),a(this._element).off(h),this._element=null},b.prototype._addEventListeners=function(){a(this._element).on(o.CLICK,this.toggle)},b._jQueryInterface=function(c){return this.each(function(){var d=a(this).data(g);if(d||a(this).data(g,d=new b(this)),"string"==typeof c){if(void 0===d[c])throw new Error('No method named "'+c+'"');d[c].call(this)}})},b._clearMenus=function(c){if(!c||c.which!==n){var d=a(q.BACKDROP)[0];d&&d.parentNode.removeChild(d);for(var e=a.makeArray(a(q.DATA_TOGGLE)),f=0;f0&&h--,c.which===m&&hdocument.documentElement.clientHeight;!this._isBodyOverflowing&&a&&(this._element.style.paddingLeft=this._scrollbarWidth+"px"),this._isBodyOverflowing&&!a&&(this._element.style.paddingRight=this._scrollbarWidth+"px")},j.prototype._resetAdjustments=function(){this._element.style.paddingLeft="",this._element.style.paddingRight=""},j.prototype._checkScrollbar=function(){this._isBodyOverflowing=document.body.clientWidth=c){var d=this._targets[this._targets.length-1];this._activeTarget!==d&&this._activate(d)}if(this._activeTarget&&a=this._offsets[e]&&(void 0===this._offsets[e+1]||a .nav-item .fade, > .fade",ACTIVE:".active",ACTIVE_CHILD:"> .nav-item > .active, > .active",DATA_TOGGLE:'[data-toggle="tab"], [data-toggle="pill"]', 7 | DROPDOWN_TOGGLE:".dropdown-toggle",DROPDOWN_ACTIVE_CHILD:"> .dropdown-menu .active"},o=function(){function b(a){c(this,b),this._element=a}return b.prototype.show=function(){var b=this;if(!this._element.parentNode||this._element.parentNode.nodeType!==Node.ELEMENT_NODE||!a(this._element).hasClass(m.ACTIVE)){var c=void 0,d=void 0,e=a(this._element).closest(n.UL)[0],g=f.getSelectorFromElement(this._element);e&&(d=a.makeArray(a(e).find(n.ACTIVE)),d=d[d.length-1]);var h=a.Event(l.HIDE,{relatedTarget:this._element}),i=a.Event(l.SHOW,{relatedTarget:d});if(d&&a(d).trigger(h),a(this._element).trigger(i),!i.isDefaultPrevented()&&!h.isDefaultPrevented()){g&&(c=a(g)[0]),this._activate(this._element,e);var j=function(){var c=a.Event(l.HIDDEN,{relatedTarget:b._element}),e=a.Event(l.SHOWN,{relatedTarget:d});a(d).trigger(c),a(b._element).trigger(e)};c?this._activate(c,c.parentNode,j):j()}}},b.prototype.dispose=function(){a.removeClass(this._element,g),this._element=null},b.prototype._activate=function(b,c,d){var e=a(c).find(n.ACTIVE_CHILD)[0],g=d&&f.supportsTransitionEnd()&&(e&&a(e).hasClass(m.FADE)||Boolean(a(c).find(n.FADE_CHILD)[0])),h=a.proxy(this._transitionComplete,this,b,e,g,d);e&&g?a(e).one(f.TRANSITION_END,h).emulateTransitionEnd(k):h(),e&&a(e).removeClass(m.IN)},b.prototype._transitionComplete=function(b,c,d,e){if(c){a(c).removeClass(m.ACTIVE);var g=a(c).find(n.DROPDOWN_ACTIVE_CHILD)[0];g&&a(g).removeClass(m.ACTIVE),c.setAttribute("aria-expanded",!1)}if(a(b).addClass(m.ACTIVE),b.setAttribute("aria-expanded",!0),d?(f.reflow(b),a(b).addClass(m.IN)):a(b).removeClass(m.FADE),b.parentNode&&a(b.parentNode).hasClass(m.DROPDOWN_MENU)){var h=a(b).closest(n.DROPDOWN)[0];h&&a(h).find(n.DROPDOWN_TOGGLE).addClass(m.ACTIVE),b.setAttribute("aria-expanded",!0)}e&&e()},b._jQueryInterface=function(c){return this.each(function(){var d=a(this),e=d.data(g);if(e||(e=e=new b(this),d.data(g,e)),"string"==typeof c){if(void 0===e[c])throw new Error('No method named "'+c+'"');e[c]()}})},e(b,null,[{key:"VERSION",get:function(){return d}}]),b}();return a(document).on(l.CLICK_DATA_API,n.DATA_TOGGLE,function(b){b.preventDefault(),o._jQueryInterface.call(a(this),"show")}),a.fn[b]=o._jQueryInterface,a.fn[b].Constructor=o,a.fn[b].noConflict=function(){return a.fn[b]=j,o._jQueryInterface},o}(jQuery),function(a){if(void 0===window.Tether)throw new Error("Bootstrap tooltips require Tether (http://tether.io/)");var b="tooltip",g="4.0.0-alpha.5",h="bs.tooltip",i="."+h,j=a.fn[b],k=150,l="bs-tether",m={animation:!0,template:'',trigger:"hover focus",title:"",delay:0,html:!1,selector:!1,placement:"top",offset:"0 0",constraints:[]},n={animation:"boolean",template:"string",title:"(string|element|function)",trigger:"string",delay:"(number|object)",html:"boolean",selector:"(string|boolean)",placement:"(string|function)",offset:"string",constraints:"array"},o={TOP:"bottom center",RIGHT:"middle left",BOTTOM:"top center",LEFT:"middle right"},p={IN:"in",OUT:"out"},q={HIDE:"hide"+i,HIDDEN:"hidden"+i,SHOW:"show"+i,SHOWN:"shown"+i,INSERTED:"inserted"+i,CLICK:"click"+i,FOCUSIN:"focusin"+i,FOCUSOUT:"focusout"+i,MOUSEENTER:"mouseenter"+i,MOUSELEAVE:"mouseleave"+i},r={FADE:"fade",IN:"in"},s={TOOLTIP:".tooltip",TOOLTIP_INNER:".tooltip-inner"},t={element:!1,enabled:!1},u={HOVER:"hover",FOCUS:"focus",CLICK:"click",MANUAL:"manual"},v=function(){function j(a,b){c(this,j),this._isEnabled=!0,this._timeout=0,this._hoverState="",this._activeTrigger={},this._tether=null,this.element=a,this.config=this._getConfig(b),this.tip=null,this._setListeners()}return j.prototype.enable=function(){this._isEnabled=!0},j.prototype.disable=function(){this._isEnabled=!1},j.prototype.toggleEnabled=function(){this._isEnabled=!this._isEnabled},j.prototype.toggle=function(b){if(b){var c=this.constructor.DATA_KEY,d=a(b.currentTarget).data(c);d||(d=new this.constructor(b.currentTarget,this._getDelegateConfig()),a(b.currentTarget).data(c,d)),d._activeTrigger.click=!d._activeTrigger.click,d._isWithActiveTrigger()?d._enter(null,d):d._leave(null,d)}else{if(a(this.getTipElement()).hasClass(r.IN))return void this._leave(null,this);this._enter(null,this)}},j.prototype.dispose=function(){clearTimeout(this._timeout),this.cleanupTether(),a.removeData(this.element,this.constructor.DATA_KEY),a(this.element).off(this.constructor.EVENT_KEY),this.tip&&a(this.tip).remove(),this._isEnabled=null,this._timeout=null,this._hoverState=null,this._activeTrigger=null,this._tether=null,this.element=null,this.config=null,this.tip=null},j.prototype.show=function(){var b=this,c=a.Event(this.constructor.Event.SHOW);if(this.isWithContent()&&this._isEnabled){a(this.element).trigger(c);var d=a.contains(this.element.ownerDocument.documentElement,this.element);if(c.isDefaultPrevented()||!d)return;var e=this.getTipElement(),g=f.getUID(this.constructor.NAME);e.setAttribute("id",g),this.element.setAttribute("aria-describedby",g),this.setContent(),this.config.animation&&a(e).addClass(r.FADE);var h="function"==typeof this.config.placement?this.config.placement.call(this,e,this.element):this.config.placement,i=this._getAttachment(h);a(e).data(this.constructor.DATA_KEY,this).appendTo(document.body),a(this.element).trigger(this.constructor.Event.INSERTED),this._tether=new Tether({attachment:i,element:e,target:this.element,classes:t,classPrefix:l,offset:this.config.offset,constraints:this.config.constraints,addTargetClasses:!1}),f.reflow(e),this._tether.position(),a(e).addClass(r.IN);var k=function(){var c=b._hoverState;b._hoverState=null,a(b.element).trigger(b.constructor.Event.SHOWN),c===p.OUT&&b._leave(null,b)};if(f.supportsTransitionEnd()&&a(this.tip).hasClass(r.FADE))return void a(this.tip).one(f.TRANSITION_END,k).emulateTransitionEnd(j._TRANSITION_DURATION);k()}},j.prototype.hide=function(b){var c=this,d=this.getTipElement(),e=a.Event(this.constructor.Event.HIDE),g=function(){c._hoverState!==p.IN&&d.parentNode&&d.parentNode.removeChild(d),c.element.removeAttribute("aria-describedby"),a(c.element).trigger(c.constructor.Event.HIDDEN),c.cleanupTether(),b&&b()};a(this.element).trigger(e),e.isDefaultPrevented()||(a(d).removeClass(r.IN),f.supportsTransitionEnd()&&a(this.tip).hasClass(r.FADE)?a(d).one(f.TRANSITION_END,g).emulateTransitionEnd(k):g(),this._hoverState="")},j.prototype.isWithContent=function(){return Boolean(this.getTitle())},j.prototype.getTipElement=function(){return this.tip=this.tip||a(this.config.template)[0]},j.prototype.setContent=function(){var b=a(this.getTipElement());this.setElementContent(b.find(s.TOOLTIP_INNER),this.getTitle()),b.removeClass(r.FADE).removeClass(r.IN),this.cleanupTether()},j.prototype.setElementContent=function(b,c){var e=this.config.html;"object"===("undefined"==typeof c?"undefined":d(c))&&(c.nodeType||c.jquery)?e?a(c).parent().is(b)||b.empty().append(c):b.text(a(c).text()):b[e?"html":"text"](c)},j.prototype.getTitle=function(){var a=this.element.getAttribute("data-original-title");return a||(a="function"==typeof this.config.title?this.config.title.call(this.element):this.config.title),a},j.prototype.cleanupTether=function(){this._tether&&this._tether.destroy()},j.prototype._getAttachment=function(a){return o[a.toUpperCase()]},j.prototype._setListeners=function(){var b=this,c=this.config.trigger.split(" ");c.forEach(function(c){if("click"===c)a(b.element).on(b.constructor.Event.CLICK,b.config.selector,a.proxy(b.toggle,b));else if(c!==u.MANUAL){var d=c===u.HOVER?b.constructor.Event.MOUSEENTER:b.constructor.Event.FOCUSIN,e=c===u.HOVER?b.constructor.Event.MOUSELEAVE:b.constructor.Event.FOCUSOUT;a(b.element).on(d,b.config.selector,a.proxy(b._enter,b)).on(e,b.config.selector,a.proxy(b._leave,b))}}),this.config.selector?this.config=a.extend({},this.config,{trigger:"manual",selector:""}):this._fixTitle()},j.prototype._fixTitle=function(){var a=d(this.element.getAttribute("data-original-title"));(this.element.getAttribute("title")||"string"!==a)&&(this.element.setAttribute("data-original-title",this.element.getAttribute("title")||""),this.element.setAttribute("title",""))},j.prototype._enter=function(b,c){var d=this.constructor.DATA_KEY;return c=c||a(b.currentTarget).data(d),c||(c=new this.constructor(b.currentTarget,this._getDelegateConfig()),a(b.currentTarget).data(d,c)),b&&(c._activeTrigger["focusin"===b.type?u.FOCUS:u.HOVER]=!0),a(c.getTipElement()).hasClass(r.IN)||c._hoverState===p.IN?void(c._hoverState=p.IN):(clearTimeout(c._timeout),c._hoverState=p.IN,c.config.delay&&c.config.delay.show?void(c._timeout=setTimeout(function(){c._hoverState===p.IN&&c.show()},c.config.delay.show)):void c.show())},j.prototype._leave=function(b,c){var d=this.constructor.DATA_KEY;if(c=c||a(b.currentTarget).data(d),c||(c=new this.constructor(b.currentTarget,this._getDelegateConfig()),a(b.currentTarget).data(d,c)),b&&(c._activeTrigger["focusout"===b.type?u.FOCUS:u.HOVER]=!1),!c._isWithActiveTrigger())return clearTimeout(c._timeout),c._hoverState=p.OUT,c.config.delay&&c.config.delay.hide?void(c._timeout=setTimeout(function(){c._hoverState===p.OUT&&c.hide()},c.config.delay.hide)):void c.hide()},j.prototype._isWithActiveTrigger=function(){for(var a in this._activeTrigger)if(this._activeTrigger[a])return!0;return!1},j.prototype._getConfig=function(c){return c=a.extend({},this.constructor.Default,a(this.element).data(),c),c.delay&&"number"==typeof c.delay&&(c.delay={show:c.delay,hide:c.delay}),f.typeCheckConfig(b,c,this.constructor.DefaultType),c},j.prototype._getDelegateConfig=function(){var a={};if(this.config)for(var b in this.config)this.constructor.Default[b]!==this.config[b]&&(a[b]=this.config[b]);return a},j._jQueryInterface=function(b){return this.each(function(){var c=a(this).data(h),e="object"===("undefined"==typeof b?"undefined":d(b))?b:null;if((c||!/dispose|hide/.test(b))&&(c||(c=new j(this,e),a(this).data(h,c)),"string"==typeof b)){if(void 0===c[b])throw new Error('No method named "'+b+'"');c[b]()}})},e(j,null,[{key:"VERSION",get:function(){return g}},{key:"Default",get:function(){return m}},{key:"NAME",get:function(){return b}},{key:"DATA_KEY",get:function(){return h}},{key:"Event",get:function(){return q}},{key:"EVENT_KEY",get:function(){return i}},{key:"DefaultType",get:function(){return n}}]),j}();return a.fn[b]=v._jQueryInterface,a.fn[b].Constructor=v,a.fn[b].noConflict=function(){return a.fn[b]=j,v._jQueryInterface},v}(jQuery));(function(f){var h="popover",i="4.0.0-alpha.5",j="bs.popover",k="."+j,l=f.fn[h],m=f.extend({},g.Default,{placement:"right",trigger:"click",content:"",template:''}),n=f.extend({},g.DefaultType,{content:"(string|element|function)"}),o={FADE:"fade",IN:"in"},p={TITLE:".popover-title",CONTENT:".popover-content"},q={HIDE:"hide"+k,HIDDEN:"hidden"+k,SHOW:"show"+k,SHOWN:"shown"+k,INSERTED:"inserted"+k,CLICK:"click"+k,FOCUSIN:"focusin"+k,FOCUSOUT:"focusout"+k,MOUSEENTER:"mouseenter"+k,MOUSELEAVE:"mouseleave"+k},r=function(g){function l(){return c(this,l),a(this,g.apply(this,arguments))}return b(l,g),l.prototype.isWithContent=function(){return this.getTitle()||this._getContent()},l.prototype.getTipElement=function(){return this.tip=this.tip||f(this.config.template)[0]},l.prototype.setContent=function(){var a=f(this.getTipElement());this.setElementContent(a.find(p.TITLE),this.getTitle()),this.setElementContent(a.find(p.CONTENT),this._getContent()),a.removeClass(o.FADE).removeClass(o.IN),this.cleanupTether()},l.prototype._getContent=function(){return this.element.getAttribute("data-content")||("function"==typeof this.config.content?this.config.content.call(this.element):this.config.content)},l._jQueryInterface=function(a){return this.each(function(){var b=f(this).data(j),c="object"===("undefined"==typeof a?"undefined":d(a))?a:null;if((b||!/destroy|hide/.test(a))&&(b||(b=new l(this,c),f(this).data(j,b)),"string"==typeof a)){if(void 0===b[a])throw new Error('No method named "'+a+'"');b[a]()}})},e(l,null,[{key:"VERSION",get:function(){return i}},{key:"Default",get:function(){return m}},{key:"NAME",get:function(){return h}},{key:"DATA_KEY",get:function(){return j}},{key:"Event",get:function(){return q}},{key:"EVENT_KEY",get:function(){return k}},{key:"DefaultType",get:function(){return n}}]),l}(g);return f.fn[h]=r._jQueryInterface,f.fn[h].Constructor=r,f.fn[h].noConflict=function(){return f.fn[h]=l,r._jQueryInterface},r})(jQuery)}(); -------------------------------------------------------------------------------- /contact.php: -------------------------------------------------------------------------------- 1 | $_POST['name'], 10 | 'email'=>$_POST['email'], 11 | 'message'=>$_POST['message'] 12 | ]; 13 | foreach($fields as $field=>$data){ 14 | if(empty($data)){ 15 | $errors[]='The '.$field . ' field is required.'; 16 | } 17 | } 18 | if(empty($errors)){ 19 | $m=new PHPMailer; 20 | $m->isSMTP(); 21 | $m->SMTPAuth=true; 22 | $m->Host='smtp.gmail.com'; 23 | $m->Username='someone@gmail.com';//replace with your email address 24 | $m->Password='password';//replace with your password 25 | $m->SMTPSecure='ssl'; 26 | $m->Port=465; 27 | 28 | $m->isHTML(); 29 | $m->Subject ='Contact form Submitted'; 30 | $m->Body='From:'.$fields['name'].'('.$fields['email'].')

'.$fields['message'].'

'; 31 | 32 | $m->FromName='Contact'; 33 | $m->AddAddress('someone@gmail.com','Some one'); 34 | if ($m->send()) { 35 | header('Location:thanks.php'); 36 | die(); 37 | }else{ 38 | $errors[]="Sorry ,Could not send email.Try again later."; 39 | } 40 | } 41 | }else{ 42 | $errors[]= 'Something went wrong'; 43 | } 44 | $_SESSION['errors']=$errors; 45 | $_SESSION['fields']=$fields; 46 | header ('Location:index.php'); -------------------------------------------------------------------------------- /helpers/security.php: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | Contact Form 15 | 16 | 17 |
18 |
19 |
20 | 21 |
22 |
  • ', $errors)?>
23 |
24 | 25 |
26 |

Contact Form

27 |
28 |
29 | 30 | > 31 |
32 |
33 | 34 | > 35 |
36 |
37 | 38 | 39 |
40 | 41 | 42 |
43 |

* means a required field

44 |
45 |
46 |
47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /libs/PHPMailerAutoload.php: -------------------------------------------------------------------------------- 1 | 8 | * @author Jim Jagielski (jimjag) 9 | * @author Andy Prevost (codeworxtech) 10 | * @author Brent R. Matzelle (original founder) 11 | * @copyright 2012 - 2014 Marcus Bointon 12 | * @copyright 2010 - 2012 Jim Jagielski 13 | * @copyright 2004 - 2009 Andy Prevost 14 | * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License 15 | * @note This program is distributed in the hope that it will be useful - WITHOUT 16 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 17 | * FITNESS FOR A PARTICULAR PURPOSE. 18 | */ 19 | 20 | /** 21 | * PHPMailer SPL autoloader. 22 | * @param string $classname The name of the class to load 23 | */ 24 | function PHPMailerAutoload($classname) 25 | { 26 | //Can't use __DIR__ as it's only in PHP 5.3+ 27 | $filename = dirname(__FILE__).DIRECTORY_SEPARATOR.'class.'.strtolower($classname).'.php'; 28 | if (is_readable($filename)) { 29 | require $filename; 30 | } 31 | } 32 | 33 | if (version_compare(PHP_VERSION, '5.1.2', '>=')) { 34 | //SPL autoloading was introduced in PHP 5.1.2 35 | if (version_compare(PHP_VERSION, '5.3.0', '>=')) { 36 | spl_autoload_register('PHPMailerAutoload', true, true); 37 | } else { 38 | spl_autoload_register('PHPMailerAutoload'); 39 | } 40 | } else { 41 | /** 42 | * Fall back to traditional autoload for old PHP versions 43 | * @param string $classname The name of the class to load 44 | */ 45 | function __autoload($classname) 46 | { 47 | PHPMailerAutoload($classname); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /libs/class.pop3.php: -------------------------------------------------------------------------------- 1 | 8 | * @author Jim Jagielski (jimjag) 9 | * @author Andy Prevost (codeworxtech) 10 | * @author Brent R. Matzelle (original founder) 11 | * @copyright 2012 - 2014 Marcus Bointon 12 | * @copyright 2010 - 2012 Jim Jagielski 13 | * @copyright 2004 - 2009 Andy Prevost 14 | * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License 15 | * @note This program is distributed in the hope that it will be useful - WITHOUT 16 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 17 | * FITNESS FOR A PARTICULAR PURPOSE. 18 | */ 19 | 20 | /** 21 | * PHPMailer POP-Before-SMTP Authentication Class. 22 | * Specifically for PHPMailer to use for RFC1939 POP-before-SMTP authentication. 23 | * Does not support APOP. 24 | * @package PHPMailer 25 | * @author Richard Davey (original author) 26 | * @author Marcus Bointon (Synchro/coolbru) 27 | * @author Jim Jagielski (jimjag) 28 | * @author Andy Prevost (codeworxtech) 29 | */ 30 | class POP3 31 | { 32 | /** 33 | * The POP3 PHPMailer Version number. 34 | * @var string 35 | * @access public 36 | */ 37 | public $Version = '5.2.16'; 38 | 39 | /** 40 | * Default POP3 port number. 41 | * @var integer 42 | * @access public 43 | */ 44 | public $POP3_PORT = 110; 45 | 46 | /** 47 | * Default timeout in seconds. 48 | * @var integer 49 | * @access public 50 | */ 51 | public $POP3_TIMEOUT = 30; 52 | 53 | /** 54 | * POP3 Carriage Return + Line Feed. 55 | * @var string 56 | * @access public 57 | * @deprecated Use the constant instead 58 | */ 59 | public $CRLF = "\r\n"; 60 | 61 | /** 62 | * Debug display level. 63 | * Options: 0 = no, 1+ = yes 64 | * @var integer 65 | * @access public 66 | */ 67 | public $do_debug = 0; 68 | 69 | /** 70 | * POP3 mail server hostname. 71 | * @var string 72 | * @access public 73 | */ 74 | public $host; 75 | 76 | /** 77 | * POP3 port number. 78 | * @var integer 79 | * @access public 80 | */ 81 | public $port; 82 | 83 | /** 84 | * POP3 Timeout Value in seconds. 85 | * @var integer 86 | * @access public 87 | */ 88 | public $tval; 89 | 90 | /** 91 | * POP3 username 92 | * @var string 93 | * @access public 94 | */ 95 | public $username; 96 | 97 | /** 98 | * POP3 password. 99 | * @var string 100 | * @access public 101 | */ 102 | public $password; 103 | 104 | /** 105 | * Resource handle for the POP3 connection socket. 106 | * @var resource 107 | * @access protected 108 | */ 109 | protected $pop_conn; 110 | 111 | /** 112 | * Are we connected? 113 | * @var boolean 114 | * @access protected 115 | */ 116 | protected $connected = false; 117 | 118 | /** 119 | * Error container. 120 | * @var array 121 | * @access protected 122 | */ 123 | protected $errors = array(); 124 | 125 | /** 126 | * Line break constant 127 | */ 128 | const CRLF = "\r\n"; 129 | 130 | /** 131 | * Simple static wrapper for all-in-one POP before SMTP 132 | * @param $host 133 | * @param integer|boolean $port The port number to connect to 134 | * @param integer|boolean $timeout The timeout value 135 | * @param string $username 136 | * @param string $password 137 | * @param integer $debug_level 138 | * @return boolean 139 | */ 140 | public static function popBeforeSmtp( 141 | $host, 142 | $port = false, 143 | $timeout = false, 144 | $username = '', 145 | $password = '', 146 | $debug_level = 0 147 | ) { 148 | $pop = new POP3; 149 | return $pop->authorise($host, $port, $timeout, $username, $password, $debug_level); 150 | } 151 | 152 | /** 153 | * Authenticate with a POP3 server. 154 | * A connect, login, disconnect sequence 155 | * appropriate for POP-before SMTP authorisation. 156 | * @access public 157 | * @param string $host The hostname to connect to 158 | * @param integer|boolean $port The port number to connect to 159 | * @param integer|boolean $timeout The timeout value 160 | * @param string $username 161 | * @param string $password 162 | * @param integer $debug_level 163 | * @return boolean 164 | */ 165 | public function authorise($host, $port = false, $timeout = false, $username = '', $password = '', $debug_level = 0) 166 | { 167 | $this->host = $host; 168 | // If no port value provided, use default 169 | if (false === $port) { 170 | $this->port = $this->POP3_PORT; 171 | } else { 172 | $this->port = (integer)$port; 173 | } 174 | // If no timeout value provided, use default 175 | if (false === $timeout) { 176 | $this->tval = $this->POP3_TIMEOUT; 177 | } else { 178 | $this->tval = (integer)$timeout; 179 | } 180 | $this->do_debug = $debug_level; 181 | $this->username = $username; 182 | $this->password = $password; 183 | // Reset the error log 184 | $this->errors = array(); 185 | // connect 186 | $result = $this->connect($this->host, $this->port, $this->tval); 187 | if ($result) { 188 | $login_result = $this->login($this->username, $this->password); 189 | if ($login_result) { 190 | $this->disconnect(); 191 | return true; 192 | } 193 | } 194 | // We need to disconnect regardless of whether the login succeeded 195 | $this->disconnect(); 196 | return false; 197 | } 198 | 199 | /** 200 | * Connect to a POP3 server. 201 | * @access public 202 | * @param string $host 203 | * @param integer|boolean $port 204 | * @param integer $tval 205 | * @return boolean 206 | */ 207 | public function connect($host, $port = false, $tval = 30) 208 | { 209 | // Are we already connected? 210 | if ($this->connected) { 211 | return true; 212 | } 213 | 214 | //On Windows this will raise a PHP Warning error if the hostname doesn't exist. 215 | //Rather than suppress it with @fsockopen, capture it cleanly instead 216 | set_error_handler(array($this, 'catchWarning')); 217 | 218 | if (false === $port) { 219 | $port = $this->POP3_PORT; 220 | } 221 | 222 | // connect to the POP3 server 223 | $this->pop_conn = fsockopen( 224 | $host, // POP3 Host 225 | $port, // Port # 226 | $errno, // Error Number 227 | $errstr, // Error Message 228 | $tval 229 | ); // Timeout (seconds) 230 | // Restore the error handler 231 | restore_error_handler(); 232 | 233 | // Did we connect? 234 | if (false === $this->pop_conn) { 235 | // It would appear not... 236 | $this->setError(array( 237 | 'error' => "Failed to connect to server $host on port $port", 238 | 'errno' => $errno, 239 | 'errstr' => $errstr 240 | )); 241 | return false; 242 | } 243 | 244 | // Increase the stream time-out 245 | stream_set_timeout($this->pop_conn, $tval, 0); 246 | 247 | // Get the POP3 server response 248 | $pop3_response = $this->getResponse(); 249 | // Check for the +OK 250 | if ($this->checkResponse($pop3_response)) { 251 | // The connection is established and the POP3 server is talking 252 | $this->connected = true; 253 | return true; 254 | } 255 | return false; 256 | } 257 | 258 | /** 259 | * Log in to the POP3 server. 260 | * Does not support APOP (RFC 2828, 4949). 261 | * @access public 262 | * @param string $username 263 | * @param string $password 264 | * @return boolean 265 | */ 266 | public function login($username = '', $password = '') 267 | { 268 | if (!$this->connected) { 269 | $this->setError('Not connected to POP3 server'); 270 | } 271 | if (empty($username)) { 272 | $username = $this->username; 273 | } 274 | if (empty($password)) { 275 | $password = $this->password; 276 | } 277 | 278 | // Send the Username 279 | $this->sendString("USER $username" . self::CRLF); 280 | $pop3_response = $this->getResponse(); 281 | if ($this->checkResponse($pop3_response)) { 282 | // Send the Password 283 | $this->sendString("PASS $password" . self::CRLF); 284 | $pop3_response = $this->getResponse(); 285 | if ($this->checkResponse($pop3_response)) { 286 | return true; 287 | } 288 | } 289 | return false; 290 | } 291 | 292 | /** 293 | * Disconnect from the POP3 server. 294 | * @access public 295 | */ 296 | public function disconnect() 297 | { 298 | $this->sendString('QUIT'); 299 | //The QUIT command may cause the daemon to exit, which will kill our connection 300 | //So ignore errors here 301 | try { 302 | @fclose($this->pop_conn); 303 | } catch (Exception $e) { 304 | //Do nothing 305 | }; 306 | } 307 | 308 | /** 309 | * Get a response from the POP3 server. 310 | * $size is the maximum number of bytes to retrieve 311 | * @param integer $size 312 | * @return string 313 | * @access protected 314 | */ 315 | protected function getResponse($size = 128) 316 | { 317 | $response = fgets($this->pop_conn, $size); 318 | if ($this->do_debug >= 1) { 319 | echo "Server -> Client: $response"; 320 | } 321 | return $response; 322 | } 323 | 324 | /** 325 | * Send raw data to the POP3 server. 326 | * @param string $string 327 | * @return integer 328 | * @access protected 329 | */ 330 | protected function sendString($string) 331 | { 332 | if ($this->pop_conn) { 333 | if ($this->do_debug >= 2) { //Show client messages when debug >= 2 334 | echo "Client -> Server: $string"; 335 | } 336 | return fwrite($this->pop_conn, $string, strlen($string)); 337 | } 338 | return 0; 339 | } 340 | 341 | /** 342 | * Checks the POP3 server response. 343 | * Looks for for +OK or -ERR. 344 | * @param string $string 345 | * @return boolean 346 | * @access protected 347 | */ 348 | protected function checkResponse($string) 349 | { 350 | if (substr($string, 0, 3) !== '+OK') { 351 | $this->setError(array( 352 | 'error' => "Server reported an error: $string", 353 | 'errno' => 0, 354 | 'errstr' => '' 355 | )); 356 | return false; 357 | } else { 358 | return true; 359 | } 360 | } 361 | 362 | /** 363 | * Add an error to the internal error store. 364 | * Also display debug output if it's enabled. 365 | * @param $error 366 | * @access protected 367 | */ 368 | protected function setError($error) 369 | { 370 | $this->errors[] = $error; 371 | if ($this->do_debug >= 1) { 372 | echo '
';
373 |             foreach ($this->errors as $error) {
374 |                 print_r($error);
375 |             }
376 |             echo '
'; 377 | } 378 | } 379 | 380 | /** 381 | * Get an array of error messages, if any. 382 | * @return array 383 | */ 384 | public function getErrors() 385 | { 386 | return $this->errors; 387 | } 388 | 389 | /** 390 | * POP3 connection error handler. 391 | * @param integer $errno 392 | * @param string $errstr 393 | * @param string $errfile 394 | * @param integer $errline 395 | * @access protected 396 | */ 397 | protected function catchWarning($errno, $errstr, $errfile, $errline) 398 | { 399 | $this->setError(array( 400 | 'error' => "Connecting to the POP3 server raised a PHP warning: ", 401 | 'errno' => $errno, 402 | 'errstr' => $errstr, 403 | 'errfile' => $errfile, 404 | 'errline' => $errline 405 | )); 406 | } 407 | } 408 | -------------------------------------------------------------------------------- /libs/class.smtp.php: -------------------------------------------------------------------------------- 1 | 8 | * @author Jim Jagielski (jimjag) 9 | * @author Andy Prevost (codeworxtech) 10 | * @author Brent R. Matzelle (original founder) 11 | * @copyright 2014 Marcus Bointon 12 | * @copyright 2010 - 2012 Jim Jagielski 13 | * @copyright 2004 - 2009 Andy Prevost 14 | * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License 15 | * @note This program is distributed in the hope that it will be useful - WITHOUT 16 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 17 | * FITNESS FOR A PARTICULAR PURPOSE. 18 | */ 19 | 20 | /** 21 | * PHPMailer RFC821 SMTP email transport class. 22 | * Implements RFC 821 SMTP commands and provides some utility methods for sending mail to an SMTP server. 23 | * @package PHPMailer 24 | * @author Chris Ryan 25 | * @author Marcus Bointon 26 | */ 27 | class SMTP 28 | { 29 | /** 30 | * The PHPMailer SMTP version number. 31 | * @var string 32 | */ 33 | const VERSION = '5.2.16'; 34 | 35 | /** 36 | * SMTP line break constant. 37 | * @var string 38 | */ 39 | const CRLF = "\r\n"; 40 | 41 | /** 42 | * The SMTP port to use if one is not specified. 43 | * @var integer 44 | */ 45 | const DEFAULT_SMTP_PORT = 25; 46 | 47 | /** 48 | * The maximum line length allowed by RFC 2822 section 2.1.1 49 | * @var integer 50 | */ 51 | const MAX_LINE_LENGTH = 998; 52 | 53 | /** 54 | * Debug level for no output 55 | */ 56 | const DEBUG_OFF = 0; 57 | 58 | /** 59 | * Debug level to show client -> server messages 60 | */ 61 | const DEBUG_CLIENT = 1; 62 | 63 | /** 64 | * Debug level to show client -> server and server -> client messages 65 | */ 66 | const DEBUG_SERVER = 2; 67 | 68 | /** 69 | * Debug level to show connection status, client -> server and server -> client messages 70 | */ 71 | const DEBUG_CONNECTION = 3; 72 | 73 | /** 74 | * Debug level to show all messages 75 | */ 76 | const DEBUG_LOWLEVEL = 4; 77 | 78 | /** 79 | * The PHPMailer SMTP Version number. 80 | * @var string 81 | * @deprecated Use the `VERSION` constant instead 82 | * @see SMTP::VERSION 83 | */ 84 | public $Version = '5.2.16'; 85 | 86 | /** 87 | * SMTP server port number. 88 | * @var integer 89 | * @deprecated This is only ever used as a default value, so use the `DEFAULT_SMTP_PORT` constant instead 90 | * @see SMTP::DEFAULT_SMTP_PORT 91 | */ 92 | public $SMTP_PORT = 25; 93 | 94 | /** 95 | * SMTP reply line ending. 96 | * @var string 97 | * @deprecated Use the `CRLF` constant instead 98 | * @see SMTP::CRLF 99 | */ 100 | public $CRLF = "\r\n"; 101 | 102 | /** 103 | * Debug output level. 104 | * Options: 105 | * * self::DEBUG_OFF (`0`) No debug output, default 106 | * * self::DEBUG_CLIENT (`1`) Client commands 107 | * * self::DEBUG_SERVER (`2`) Client commands and server responses 108 | * * self::DEBUG_CONNECTION (`3`) As DEBUG_SERVER plus connection status 109 | * * self::DEBUG_LOWLEVEL (`4`) Low-level data output, all messages 110 | * @var integer 111 | */ 112 | public $do_debug = self::DEBUG_OFF; 113 | 114 | /** 115 | * How to handle debug output. 116 | * Options: 117 | * * `echo` Output plain-text as-is, appropriate for CLI 118 | * * `html` Output escaped, line breaks converted to `
`, appropriate for browser output 119 | * * `error_log` Output to error log as configured in php.ini 120 | * 121 | * Alternatively, you can provide a callable expecting two params: a message string and the debug level: 122 | * 123 | * $smtp->Debugoutput = function($str, $level) {echo "debug level $level; message: $str";}; 124 | * 125 | * @var string|callable 126 | */ 127 | public $Debugoutput = 'echo'; 128 | 129 | /** 130 | * Whether to use VERP. 131 | * @link http://en.wikipedia.org/wiki/Variable_envelope_return_path 132 | * @link http://www.postfix.org/VERP_README.html Info on VERP 133 | * @var boolean 134 | */ 135 | public $do_verp = false; 136 | 137 | /** 138 | * The timeout value for connection, in seconds. 139 | * Default of 5 minutes (300sec) is from RFC2821 section 4.5.3.2 140 | * This needs to be quite high to function correctly with hosts using greetdelay as an anti-spam measure. 141 | * @link http://tools.ietf.org/html/rfc2821#section-4.5.3.2 142 | * @var integer 143 | */ 144 | public $Timeout = 300; 145 | 146 | /** 147 | * How long to wait for commands to complete, in seconds. 148 | * Default of 5 minutes (300sec) is from RFC2821 section 4.5.3.2 149 | * @var integer 150 | */ 151 | public $Timelimit = 300; 152 | 153 | /** 154 | * The socket for the server connection. 155 | * @var resource 156 | */ 157 | protected $smtp_conn; 158 | 159 | /** 160 | * Error information, if any, for the last SMTP command. 161 | * @var array 162 | */ 163 | protected $error = array( 164 | 'error' => '', 165 | 'detail' => '', 166 | 'smtp_code' => '', 167 | 'smtp_code_ex' => '' 168 | ); 169 | 170 | /** 171 | * The reply the server sent to us for HELO. 172 | * If null, no HELO string has yet been received. 173 | * @var string|null 174 | */ 175 | protected $helo_rply = null; 176 | 177 | /** 178 | * The set of SMTP extensions sent in reply to EHLO command. 179 | * Indexes of the array are extension names. 180 | * Value at index 'HELO' or 'EHLO' (according to command that was sent) 181 | * represents the server name. In case of HELO it is the only element of the array. 182 | * Other values can be boolean TRUE or an array containing extension options. 183 | * If null, no HELO/EHLO string has yet been received. 184 | * @var array|null 185 | */ 186 | protected $server_caps = null; 187 | 188 | /** 189 | * The most recent reply received from the server. 190 | * @var string 191 | */ 192 | protected $last_reply = ''; 193 | 194 | /** 195 | * Output debugging info via a user-selected method. 196 | * @see SMTP::$Debugoutput 197 | * @see SMTP::$do_debug 198 | * @param string $str Debug string to output 199 | * @param integer $level The debug level of this message; see DEBUG_* constants 200 | * @return void 201 | */ 202 | protected function edebug($str, $level = 0) 203 | { 204 | if ($level > $this->do_debug) { 205 | return; 206 | } 207 | //Avoid clash with built-in function names 208 | if (!in_array($this->Debugoutput, array('error_log', 'html', 'echo')) and is_callable($this->Debugoutput)) { 209 | call_user_func($this->Debugoutput, $str, $level); 210 | return; 211 | } 212 | switch ($this->Debugoutput) { 213 | case 'error_log': 214 | //Don't output, just log 215 | error_log($str); 216 | break; 217 | case 'html': 218 | //Cleans up output a bit for a better looking, HTML-safe output 219 | echo htmlentities( 220 | preg_replace('/[\r\n]+/', '', $str), 221 | ENT_QUOTES, 222 | 'UTF-8' 223 | ) 224 | . "
\n"; 225 | break; 226 | case 'echo': 227 | default: 228 | //Normalize line breaks 229 | $str = preg_replace('/(\r\n|\r|\n)/ms', "\n", $str); 230 | echo gmdate('Y-m-d H:i:s') . "\t" . str_replace( 231 | "\n", 232 | "\n \t ", 233 | trim($str) 234 | )."\n"; 235 | } 236 | } 237 | 238 | /** 239 | * Connect to an SMTP server. 240 | * @param string $host SMTP server IP or host name 241 | * @param integer $port The port number to connect to 242 | * @param integer $timeout How long to wait for the connection to open 243 | * @param array $options An array of options for stream_context_create() 244 | * @access public 245 | * @return boolean 246 | */ 247 | public function connect($host, $port = null, $timeout = 30, $options = array()) 248 | { 249 | static $streamok; 250 | //This is enabled by default since 5.0.0 but some providers disable it 251 | //Check this once and cache the result 252 | if (is_null($streamok)) { 253 | $streamok = function_exists('stream_socket_client'); 254 | } 255 | // Clear errors to avoid confusion 256 | $this->setError(''); 257 | // Make sure we are __not__ connected 258 | if ($this->connected()) { 259 | // Already connected, generate error 260 | $this->setError('Already connected to a server'); 261 | return false; 262 | } 263 | if (empty($port)) { 264 | $port = self::DEFAULT_SMTP_PORT; 265 | } 266 | // Connect to the SMTP server 267 | $this->edebug( 268 | "Connection: opening to $host:$port, timeout=$timeout, options=".var_export($options, true), 269 | self::DEBUG_CONNECTION 270 | ); 271 | $errno = 0; 272 | $errstr = ''; 273 | if ($streamok) { 274 | $socket_context = stream_context_create($options); 275 | set_error_handler(array($this, 'errorHandler')); 276 | $this->smtp_conn = stream_socket_client( 277 | $host . ":" . $port, 278 | $errno, 279 | $errstr, 280 | $timeout, 281 | STREAM_CLIENT_CONNECT, 282 | $socket_context 283 | ); 284 | restore_error_handler(); 285 | } else { 286 | //Fall back to fsockopen which should work in more places, but is missing some features 287 | $this->edebug( 288 | "Connection: stream_socket_client not available, falling back to fsockopen", 289 | self::DEBUG_CONNECTION 290 | ); 291 | set_error_handler(array($this, 'errorHandler')); 292 | $this->smtp_conn = fsockopen( 293 | $host, 294 | $port, 295 | $errno, 296 | $errstr, 297 | $timeout 298 | ); 299 | restore_error_handler(); 300 | } 301 | // Verify we connected properly 302 | if (!is_resource($this->smtp_conn)) { 303 | $this->setError( 304 | 'Failed to connect to server', 305 | $errno, 306 | $errstr 307 | ); 308 | $this->edebug( 309 | 'SMTP ERROR: ' . $this->error['error'] 310 | . ": $errstr ($errno)", 311 | self::DEBUG_CLIENT 312 | ); 313 | return false; 314 | } 315 | $this->edebug('Connection: opened', self::DEBUG_CONNECTION); 316 | // SMTP server can take longer to respond, give longer timeout for first read 317 | // Windows does not have support for this timeout function 318 | if (substr(PHP_OS, 0, 3) != 'WIN') { 319 | $max = ini_get('max_execution_time'); 320 | // Don't bother if unlimited 321 | if ($max != 0 && $timeout > $max) { 322 | @set_time_limit($timeout); 323 | } 324 | stream_set_timeout($this->smtp_conn, $timeout, 0); 325 | } 326 | // Get any announcement 327 | $announce = $this->get_lines(); 328 | $this->edebug('SERVER -> CLIENT: ' . $announce, self::DEBUG_SERVER); 329 | return true; 330 | } 331 | 332 | /** 333 | * Initiate a TLS (encrypted) session. 334 | * @access public 335 | * @return boolean 336 | */ 337 | public function startTLS() 338 | { 339 | if (!$this->sendCommand('STARTTLS', 'STARTTLS', 220)) { 340 | return false; 341 | } 342 | 343 | //Allow the best TLS version(s) we can 344 | $crypto_method = STREAM_CRYPTO_METHOD_TLS_CLIENT; 345 | 346 | //PHP 5.6.7 dropped inclusion of TLS 1.1 and 1.2 in STREAM_CRYPTO_METHOD_TLS_CLIENT 347 | //so add them back in manually if we can 348 | if (defined('STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT')) { 349 | $crypto_method |= STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT; 350 | $crypto_method |= STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT; 351 | } 352 | 353 | // Begin encrypted connection 354 | if (!stream_socket_enable_crypto( 355 | $this->smtp_conn, 356 | true, 357 | $crypto_method 358 | )) { 359 | return false; 360 | } 361 | return true; 362 | } 363 | 364 | /** 365 | * Perform SMTP authentication. 366 | * Must be run after hello(). 367 | * @see hello() 368 | * @param string $username The user name 369 | * @param string $password The password 370 | * @param string $authtype The auth type (PLAIN, LOGIN, NTLM, CRAM-MD5, XOAUTH2) 371 | * @param string $realm The auth realm for NTLM 372 | * @param string $workstation The auth workstation for NTLM 373 | * @param null|OAuth $OAuth An optional OAuth instance (@see PHPMailerOAuth) 374 | * @return bool True if successfully authenticated.* @access public 375 | */ 376 | public function authenticate( 377 | $username, 378 | $password, 379 | $authtype = null, 380 | $realm = '', 381 | $workstation = '', 382 | $OAuth = null 383 | ) { 384 | if (!$this->server_caps) { 385 | $this->setError('Authentication is not allowed before HELO/EHLO'); 386 | return false; 387 | } 388 | 389 | if (array_key_exists('EHLO', $this->server_caps)) { 390 | // SMTP extensions are available. Let's try to find a proper authentication method 391 | 392 | if (!array_key_exists('AUTH', $this->server_caps)) { 393 | $this->setError('Authentication is not allowed at this stage'); 394 | // 'at this stage' means that auth may be allowed after the stage changes 395 | // e.g. after STARTTLS 396 | return false; 397 | } 398 | 399 | self::edebug('Auth method requested: ' . ($authtype ? $authtype : 'UNKNOWN'), self::DEBUG_LOWLEVEL); 400 | self::edebug( 401 | 'Auth methods available on the server: ' . implode(',', $this->server_caps['AUTH']), 402 | self::DEBUG_LOWLEVEL 403 | ); 404 | 405 | if (empty($authtype)) { 406 | foreach (array('CRAM-MD5', 'LOGIN', 'PLAIN', 'NTLM', 'XOAUTH2') as $method) { 407 | if (in_array($method, $this->server_caps['AUTH'])) { 408 | $authtype = $method; 409 | break; 410 | } 411 | } 412 | if (empty($authtype)) { 413 | $this->setError('No supported authentication methods found'); 414 | return false; 415 | } 416 | self::edebug('Auth method selected: '.$authtype, self::DEBUG_LOWLEVEL); 417 | } 418 | 419 | if (!in_array($authtype, $this->server_caps['AUTH'])) { 420 | $this->setError("The requested authentication method \"$authtype\" is not supported by the server"); 421 | return false; 422 | } 423 | } elseif (empty($authtype)) { 424 | $authtype = 'LOGIN'; 425 | } 426 | switch ($authtype) { 427 | case 'PLAIN': 428 | // Start authentication 429 | if (!$this->sendCommand('AUTH', 'AUTH PLAIN', 334)) { 430 | return false; 431 | } 432 | // Send encoded username and password 433 | if (!$this->sendCommand( 434 | 'User & Password', 435 | base64_encode("\0" . $username . "\0" . $password), 436 | 235 437 | ) 438 | ) { 439 | return false; 440 | } 441 | break; 442 | case 'LOGIN': 443 | // Start authentication 444 | if (!$this->sendCommand('AUTH', 'AUTH LOGIN', 334)) { 445 | return false; 446 | } 447 | if (!$this->sendCommand("Username", base64_encode($username), 334)) { 448 | return false; 449 | } 450 | if (!$this->sendCommand("Password", base64_encode($password), 235)) { 451 | return false; 452 | } 453 | break; 454 | case 'XOAUTH2': 455 | //If the OAuth Instance is not set. Can be a case when PHPMailer is used 456 | //instead of PHPMailerOAuth 457 | if (is_null($OAuth)) { 458 | return false; 459 | } 460 | $oauth = $OAuth->getOauth64(); 461 | 462 | // Start authentication 463 | if (!$this->sendCommand('AUTH', 'AUTH XOAUTH2 ' . $oauth, 235)) { 464 | return false; 465 | } 466 | break; 467 | case 'NTLM': 468 | /* 469 | * ntlm_sasl_client.php 470 | * Bundled with Permission 471 | * 472 | * How to telnet in windows: 473 | * http://technet.microsoft.com/en-us/library/aa995718%28EXCHG.65%29.aspx 474 | * PROTOCOL Docs http://curl.haxx.se/rfc/ntlm.html#ntlmSmtpAuthentication 475 | */ 476 | require_once 'extras/ntlm_sasl_client.php'; 477 | $temp = new stdClass; 478 | $ntlm_client = new ntlm_sasl_client_class; 479 | //Check that functions are available 480 | if (!$ntlm_client->initialize($temp)) { 481 | $this->setError($temp->error); 482 | $this->edebug( 483 | 'You need to enable some modules in your php.ini file: ' 484 | . $this->error['error'], 485 | self::DEBUG_CLIENT 486 | ); 487 | return false; 488 | } 489 | //msg1 490 | $msg1 = $ntlm_client->typeMsg1($realm, $workstation); //msg1 491 | 492 | if (!$this->sendCommand( 493 | 'AUTH NTLM', 494 | 'AUTH NTLM ' . base64_encode($msg1), 495 | 334 496 | ) 497 | ) { 498 | return false; 499 | } 500 | //Though 0 based, there is a white space after the 3 digit number 501 | //msg2 502 | $challenge = substr($this->last_reply, 3); 503 | $challenge = base64_decode($challenge); 504 | $ntlm_res = $ntlm_client->NTLMResponse( 505 | substr($challenge, 24, 8), 506 | $password 507 | ); 508 | //msg3 509 | $msg3 = $ntlm_client->typeMsg3( 510 | $ntlm_res, 511 | $username, 512 | $realm, 513 | $workstation 514 | ); 515 | // send encoded username 516 | return $this->sendCommand('Username', base64_encode($msg3), 235); 517 | case 'CRAM-MD5': 518 | // Start authentication 519 | if (!$this->sendCommand('AUTH CRAM-MD5', 'AUTH CRAM-MD5', 334)) { 520 | return false; 521 | } 522 | // Get the challenge 523 | $challenge = base64_decode(substr($this->last_reply, 4)); 524 | 525 | // Build the response 526 | $response = $username . ' ' . $this->hmac($challenge, $password); 527 | 528 | // send encoded credentials 529 | return $this->sendCommand('Username', base64_encode($response), 235); 530 | default: 531 | $this->setError("Authentication method \"$authtype\" is not supported"); 532 | return false; 533 | } 534 | return true; 535 | } 536 | 537 | /** 538 | * Calculate an MD5 HMAC hash. 539 | * Works like hash_hmac('md5', $data, $key) 540 | * in case that function is not available 541 | * @param string $data The data to hash 542 | * @param string $key The key to hash with 543 | * @access protected 544 | * @return string 545 | */ 546 | protected function hmac($data, $key) 547 | { 548 | if (function_exists('hash_hmac')) { 549 | return hash_hmac('md5', $data, $key); 550 | } 551 | 552 | // The following borrowed from 553 | // http://php.net/manual/en/function.mhash.php#27225 554 | 555 | // RFC 2104 HMAC implementation for php. 556 | // Creates an md5 HMAC. 557 | // Eliminates the need to install mhash to compute a HMAC 558 | // by Lance Rushing 559 | 560 | $bytelen = 64; // byte length for md5 561 | if (strlen($key) > $bytelen) { 562 | $key = pack('H*', md5($key)); 563 | } 564 | $key = str_pad($key, $bytelen, chr(0x00)); 565 | $ipad = str_pad('', $bytelen, chr(0x36)); 566 | $opad = str_pad('', $bytelen, chr(0x5c)); 567 | $k_ipad = $key ^ $ipad; 568 | $k_opad = $key ^ $opad; 569 | 570 | return md5($k_opad . pack('H*', md5($k_ipad . $data))); 571 | } 572 | 573 | /** 574 | * Check connection state. 575 | * @access public 576 | * @return boolean True if connected. 577 | */ 578 | public function connected() 579 | { 580 | if (is_resource($this->smtp_conn)) { 581 | $sock_status = stream_get_meta_data($this->smtp_conn); 582 | if ($sock_status['eof']) { 583 | // The socket is valid but we are not connected 584 | $this->edebug( 585 | 'SMTP NOTICE: EOF caught while checking if connected', 586 | self::DEBUG_CLIENT 587 | ); 588 | $this->close(); 589 | return false; 590 | } 591 | return true; // everything looks good 592 | } 593 | return false; 594 | } 595 | 596 | /** 597 | * Close the socket and clean up the state of the class. 598 | * Don't use this function without first trying to use QUIT. 599 | * @see quit() 600 | * @access public 601 | * @return void 602 | */ 603 | public function close() 604 | { 605 | $this->setError(''); 606 | $this->server_caps = null; 607 | $this->helo_rply = null; 608 | if (is_resource($this->smtp_conn)) { 609 | // close the connection and cleanup 610 | fclose($this->smtp_conn); 611 | $this->smtp_conn = null; //Makes for cleaner serialization 612 | $this->edebug('Connection: closed', self::DEBUG_CONNECTION); 613 | } 614 | } 615 | 616 | /** 617 | * Send an SMTP DATA command. 618 | * Issues a data command and sends the msg_data to the server, 619 | * finializing the mail transaction. $msg_data is the message 620 | * that is to be send with the headers. Each header needs to be 621 | * on a single line followed by a with the message headers 622 | * and the message body being separated by and additional . 623 | * Implements rfc 821: DATA 624 | * @param string $msg_data Message data to send 625 | * @access public 626 | * @return boolean 627 | */ 628 | public function data($msg_data) 629 | { 630 | //This will use the standard timelimit 631 | if (!$this->sendCommand('DATA', 'DATA', 354)) { 632 | return false; 633 | } 634 | 635 | /* The server is ready to accept data! 636 | * According to rfc821 we should not send more than 1000 characters on a single line (including the CRLF) 637 | * so we will break the data up into lines by \r and/or \n then if needed we will break each of those into 638 | * smaller lines to fit within the limit. 639 | * We will also look for lines that start with a '.' and prepend an additional '.'. 640 | * NOTE: this does not count towards line-length limit. 641 | */ 642 | 643 | // Normalize line breaks before exploding 644 | $lines = explode("\n", str_replace(array("\r\n", "\r"), "\n", $msg_data)); 645 | 646 | /* To distinguish between a complete RFC822 message and a plain message body, we check if the first field 647 | * of the first line (':' separated) does not contain a space then it _should_ be a header and we will 648 | * process all lines before a blank line as headers. 649 | */ 650 | 651 | $field = substr($lines[0], 0, strpos($lines[0], ':')); 652 | $in_headers = false; 653 | if (!empty($field) && strpos($field, ' ') === false) { 654 | $in_headers = true; 655 | } 656 | 657 | foreach ($lines as $line) { 658 | $lines_out = array(); 659 | if ($in_headers and $line == '') { 660 | $in_headers = false; 661 | } 662 | //Break this line up into several smaller lines if it's too long 663 | //Micro-optimisation: isset($str[$len]) is faster than (strlen($str) > $len), 664 | while (isset($line[self::MAX_LINE_LENGTH])) { 665 | //Working backwards, try to find a space within the last MAX_LINE_LENGTH chars of the line to break on 666 | //so as to avoid breaking in the middle of a word 667 | $pos = strrpos(substr($line, 0, self::MAX_LINE_LENGTH), ' '); 668 | //Deliberately matches both false and 0 669 | if (!$pos) { 670 | //No nice break found, add a hard break 671 | $pos = self::MAX_LINE_LENGTH - 1; 672 | $lines_out[] = substr($line, 0, $pos); 673 | $line = substr($line, $pos); 674 | } else { 675 | //Break at the found point 676 | $lines_out[] = substr($line, 0, $pos); 677 | //Move along by the amount we dealt with 678 | $line = substr($line, $pos + 1); 679 | } 680 | //If processing headers add a LWSP-char to the front of new line RFC822 section 3.1.1 681 | if ($in_headers) { 682 | $line = "\t" . $line; 683 | } 684 | } 685 | $lines_out[] = $line; 686 | 687 | //Send the lines to the server 688 | foreach ($lines_out as $line_out) { 689 | //RFC2821 section 4.5.2 690 | if (!empty($line_out) and $line_out[0] == '.') { 691 | $line_out = '.' . $line_out; 692 | } 693 | $this->client_send($line_out . self::CRLF); 694 | } 695 | } 696 | 697 | //Message data has been sent, complete the command 698 | //Increase timelimit for end of DATA command 699 | $savetimelimit = $this->Timelimit; 700 | $this->Timelimit = $this->Timelimit * 2; 701 | $result = $this->sendCommand('DATA END', '.', 250); 702 | //Restore timelimit 703 | $this->Timelimit = $savetimelimit; 704 | return $result; 705 | } 706 | 707 | /** 708 | * Send an SMTP HELO or EHLO command. 709 | * Used to identify the sending server to the receiving server. 710 | * This makes sure that client and server are in a known state. 711 | * Implements RFC 821: HELO 712 | * and RFC 2821 EHLO. 713 | * @param string $host The host name or IP to connect to 714 | * @access public 715 | * @return boolean 716 | */ 717 | public function hello($host = '') 718 | { 719 | //Try extended hello first (RFC 2821) 720 | return (boolean)($this->sendHello('EHLO', $host) or $this->sendHello('HELO', $host)); 721 | } 722 | 723 | /** 724 | * Send an SMTP HELO or EHLO command. 725 | * Low-level implementation used by hello() 726 | * @see hello() 727 | * @param string $hello The HELO string 728 | * @param string $host The hostname to say we are 729 | * @access protected 730 | * @return boolean 731 | */ 732 | protected function sendHello($hello, $host) 733 | { 734 | $noerror = $this->sendCommand($hello, $hello . ' ' . $host, 250); 735 | $this->helo_rply = $this->last_reply; 736 | if ($noerror) { 737 | $this->parseHelloFields($hello); 738 | } else { 739 | $this->server_caps = null; 740 | } 741 | return $noerror; 742 | } 743 | 744 | /** 745 | * Parse a reply to HELO/EHLO command to discover server extensions. 746 | * In case of HELO, the only parameter that can be discovered is a server name. 747 | * @access protected 748 | * @param string $type - 'HELO' or 'EHLO' 749 | */ 750 | protected function parseHelloFields($type) 751 | { 752 | $this->server_caps = array(); 753 | $lines = explode("\n", $this->helo_rply); 754 | 755 | foreach ($lines as $n => $s) { 756 | //First 4 chars contain response code followed by - or space 757 | $s = trim(substr($s, 4)); 758 | if (empty($s)) { 759 | continue; 760 | } 761 | $fields = explode(' ', $s); 762 | if (!empty($fields)) { 763 | if (!$n) { 764 | $name = $type; 765 | $fields = $fields[0]; 766 | } else { 767 | $name = array_shift($fields); 768 | switch ($name) { 769 | case 'SIZE': 770 | $fields = ($fields ? $fields[0] : 0); 771 | break; 772 | case 'AUTH': 773 | if (!is_array($fields)) { 774 | $fields = array(); 775 | } 776 | break; 777 | default: 778 | $fields = true; 779 | } 780 | } 781 | $this->server_caps[$name] = $fields; 782 | } 783 | } 784 | } 785 | 786 | /** 787 | * Send an SMTP MAIL command. 788 | * Starts a mail transaction from the email address specified in 789 | * $from. Returns true if successful or false otherwise. If True 790 | * the mail transaction is started and then one or more recipient 791 | * commands may be called followed by a data command. 792 | * Implements rfc 821: MAIL FROM: 793 | * @param string $from Source address of this message 794 | * @access public 795 | * @return boolean 796 | */ 797 | public function mail($from) 798 | { 799 | $useVerp = ($this->do_verp ? ' XVERP' : ''); 800 | return $this->sendCommand( 801 | 'MAIL FROM', 802 | 'MAIL FROM:<' . $from . '>' . $useVerp, 803 | 250 804 | ); 805 | } 806 | 807 | /** 808 | * Send an SMTP QUIT command. 809 | * Closes the socket if there is no error or the $close_on_error argument is true. 810 | * Implements from rfc 821: QUIT 811 | * @param boolean $close_on_error Should the connection close if an error occurs? 812 | * @access public 813 | * @return boolean 814 | */ 815 | public function quit($close_on_error = true) 816 | { 817 | $noerror = $this->sendCommand('QUIT', 'QUIT', 221); 818 | $err = $this->error; //Save any error 819 | if ($noerror or $close_on_error) { 820 | $this->close(); 821 | $this->error = $err; //Restore any error from the quit command 822 | } 823 | return $noerror; 824 | } 825 | 826 | /** 827 | * Send an SMTP RCPT command. 828 | * Sets the TO argument to $toaddr. 829 | * Returns true if the recipient was accepted false if it was rejected. 830 | * Implements from rfc 821: RCPT TO: 831 | * @param string $address The address the message is being sent to 832 | * @access public 833 | * @return boolean 834 | */ 835 | public function recipient($address) 836 | { 837 | return $this->sendCommand( 838 | 'RCPT TO', 839 | 'RCPT TO:<' . $address . '>', 840 | array(250, 251) 841 | ); 842 | } 843 | 844 | /** 845 | * Send an SMTP RSET command. 846 | * Abort any transaction that is currently in progress. 847 | * Implements rfc 821: RSET 848 | * @access public 849 | * @return boolean True on success. 850 | */ 851 | public function reset() 852 | { 853 | return $this->sendCommand('RSET', 'RSET', 250); 854 | } 855 | 856 | /** 857 | * Send a command to an SMTP server and check its return code. 858 | * @param string $command The command name - not sent to the server 859 | * @param string $commandstring The actual command to send 860 | * @param integer|array $expect One or more expected integer success codes 861 | * @access protected 862 | * @return boolean True on success. 863 | */ 864 | protected function sendCommand($command, $commandstring, $expect) 865 | { 866 | if (!$this->connected()) { 867 | $this->setError("Called $command without being connected"); 868 | return false; 869 | } 870 | //Reject line breaks in all commands 871 | if (strpos($commandstring, "\n") !== false or strpos($commandstring, "\r") !== false) { 872 | $this->setError("Command '$command' contained line breaks"); 873 | return false; 874 | } 875 | $this->client_send($commandstring . self::CRLF); 876 | 877 | $this->last_reply = $this->get_lines(); 878 | // Fetch SMTP code and possible error code explanation 879 | $matches = array(); 880 | if (preg_match("/^([0-9]{3})[ -](?:([0-9]\\.[0-9]\\.[0-9]) )?/", $this->last_reply, $matches)) { 881 | $code = $matches[1]; 882 | $code_ex = (count($matches) > 2 ? $matches[2] : null); 883 | // Cut off error code from each response line 884 | $detail = preg_replace( 885 | "/{$code}[ -]".($code_ex ? str_replace('.', '\\.', $code_ex).' ' : '')."/m", 886 | '', 887 | $this->last_reply 888 | ); 889 | } else { 890 | // Fall back to simple parsing if regex fails 891 | $code = substr($this->last_reply, 0, 3); 892 | $code_ex = null; 893 | $detail = substr($this->last_reply, 4); 894 | } 895 | 896 | $this->edebug('SERVER -> CLIENT: ' . $this->last_reply, self::DEBUG_SERVER); 897 | 898 | if (!in_array($code, (array)$expect)) { 899 | $this->setError( 900 | "$command command failed", 901 | $detail, 902 | $code, 903 | $code_ex 904 | ); 905 | $this->edebug( 906 | 'SMTP ERROR: ' . $this->error['error'] . ': ' . $this->last_reply, 907 | self::DEBUG_CLIENT 908 | ); 909 | return false; 910 | } 911 | 912 | $this->setError(''); 913 | return true; 914 | } 915 | 916 | /** 917 | * Send an SMTP SAML command. 918 | * Starts a mail transaction from the email address specified in $from. 919 | * Returns true if successful or false otherwise. If True 920 | * the mail transaction is started and then one or more recipient 921 | * commands may be called followed by a data command. This command 922 | * will send the message to the users terminal if they are logged 923 | * in and send them an email. 924 | * Implements rfc 821: SAML FROM: 925 | * @param string $from The address the message is from 926 | * @access public 927 | * @return boolean 928 | */ 929 | public function sendAndMail($from) 930 | { 931 | return $this->sendCommand('SAML', "SAML FROM:$from", 250); 932 | } 933 | 934 | /** 935 | * Send an SMTP VRFY command. 936 | * @param string $name The name to verify 937 | * @access public 938 | * @return boolean 939 | */ 940 | public function verify($name) 941 | { 942 | return $this->sendCommand('VRFY', "VRFY $name", array(250, 251)); 943 | } 944 | 945 | /** 946 | * Send an SMTP NOOP command. 947 | * Used to keep keep-alives alive, doesn't actually do anything 948 | * @access public 949 | * @return boolean 950 | */ 951 | public function noop() 952 | { 953 | return $this->sendCommand('NOOP', 'NOOP', 250); 954 | } 955 | 956 | /** 957 | * Send an SMTP TURN command. 958 | * This is an optional command for SMTP that this class does not support. 959 | * This method is here to make the RFC821 Definition complete for this class 960 | * and _may_ be implemented in future 961 | * Implements from rfc 821: TURN 962 | * @access public 963 | * @return boolean 964 | */ 965 | public function turn() 966 | { 967 | $this->setError('The SMTP TURN command is not implemented'); 968 | $this->edebug('SMTP NOTICE: ' . $this->error['error'], self::DEBUG_CLIENT); 969 | return false; 970 | } 971 | 972 | /** 973 | * Send raw data to the server. 974 | * @param string $data The data to send 975 | * @access public 976 | * @return integer|boolean The number of bytes sent to the server or false on error 977 | */ 978 | public function client_send($data) 979 | { 980 | $this->edebug("CLIENT -> SERVER: $data", self::DEBUG_CLIENT); 981 | return fwrite($this->smtp_conn, $data); 982 | } 983 | 984 | /** 985 | * Get the latest error. 986 | * @access public 987 | * @return array 988 | */ 989 | public function getError() 990 | { 991 | return $this->error; 992 | } 993 | 994 | /** 995 | * Get SMTP extensions available on the server 996 | * @access public 997 | * @return array|null 998 | */ 999 | public function getServerExtList() 1000 | { 1001 | return $this->server_caps; 1002 | } 1003 | 1004 | /** 1005 | * A multipurpose method 1006 | * The method works in three ways, dependent on argument value and current state 1007 | * 1. HELO/EHLO was not sent - returns null and set up $this->error 1008 | * 2. HELO was sent 1009 | * $name = 'HELO': returns server name 1010 | * $name = 'EHLO': returns boolean false 1011 | * $name = any string: returns null and set up $this->error 1012 | * 3. EHLO was sent 1013 | * $name = 'HELO'|'EHLO': returns server name 1014 | * $name = any string: if extension $name exists, returns boolean True 1015 | * or its options. Otherwise returns boolean False 1016 | * In other words, one can use this method to detect 3 conditions: 1017 | * - null returned: handshake was not or we don't know about ext (refer to $this->error) 1018 | * - false returned: the requested feature exactly not exists 1019 | * - positive value returned: the requested feature exists 1020 | * @param string $name Name of SMTP extension or 'HELO'|'EHLO' 1021 | * @return mixed 1022 | */ 1023 | public function getServerExt($name) 1024 | { 1025 | if (!$this->server_caps) { 1026 | $this->setError('No HELO/EHLO was sent'); 1027 | return null; 1028 | } 1029 | 1030 | // the tight logic knot ;) 1031 | if (!array_key_exists($name, $this->server_caps)) { 1032 | if ($name == 'HELO') { 1033 | return $this->server_caps['EHLO']; 1034 | } 1035 | if ($name == 'EHLO' || array_key_exists('EHLO', $this->server_caps)) { 1036 | return false; 1037 | } 1038 | $this->setError('HELO handshake was used. Client knows nothing about server extensions'); 1039 | return null; 1040 | } 1041 | 1042 | return $this->server_caps[$name]; 1043 | } 1044 | 1045 | /** 1046 | * Get the last reply from the server. 1047 | * @access public 1048 | * @return string 1049 | */ 1050 | public function getLastReply() 1051 | { 1052 | return $this->last_reply; 1053 | } 1054 | 1055 | /** 1056 | * Read the SMTP server's response. 1057 | * Either before eof or socket timeout occurs on the operation. 1058 | * With SMTP we can tell if we have more lines to read if the 1059 | * 4th character is '-' symbol. If it is a space then we don't 1060 | * need to read anything else. 1061 | * @access protected 1062 | * @return string 1063 | */ 1064 | protected function get_lines() 1065 | { 1066 | // If the connection is bad, give up straight away 1067 | if (!is_resource($this->smtp_conn)) { 1068 | return ''; 1069 | } 1070 | $data = ''; 1071 | $endtime = 0; 1072 | stream_set_timeout($this->smtp_conn, $this->Timeout); 1073 | if ($this->Timelimit > 0) { 1074 | $endtime = time() + $this->Timelimit; 1075 | } 1076 | while (is_resource($this->smtp_conn) && !feof($this->smtp_conn)) { 1077 | $str = @fgets($this->smtp_conn, 515); 1078 | $this->edebug("SMTP -> get_lines(): \$data is \"$data\"", self::DEBUG_LOWLEVEL); 1079 | $this->edebug("SMTP -> get_lines(): \$str is \"$str\"", self::DEBUG_LOWLEVEL); 1080 | $data .= $str; 1081 | // If 4th character is a space, we are done reading, break the loop, micro-optimisation over strlen 1082 | if ((isset($str[3]) and $str[3] == ' ')) { 1083 | break; 1084 | } 1085 | // Timed-out? Log and break 1086 | $info = stream_get_meta_data($this->smtp_conn); 1087 | if ($info['timed_out']) { 1088 | $this->edebug( 1089 | 'SMTP -> get_lines(): timed-out (' . $this->Timeout . ' sec)', 1090 | self::DEBUG_LOWLEVEL 1091 | ); 1092 | break; 1093 | } 1094 | // Now check if reads took too long 1095 | if ($endtime and time() > $endtime) { 1096 | $this->edebug( 1097 | 'SMTP -> get_lines(): timelimit reached ('. 1098 | $this->Timelimit . ' sec)', 1099 | self::DEBUG_LOWLEVEL 1100 | ); 1101 | break; 1102 | } 1103 | } 1104 | return $data; 1105 | } 1106 | 1107 | /** 1108 | * Enable or disable VERP address generation. 1109 | * @param boolean $enabled 1110 | */ 1111 | public function setVerp($enabled = false) 1112 | { 1113 | $this->do_verp = $enabled; 1114 | } 1115 | 1116 | /** 1117 | * Get VERP address generation mode. 1118 | * @return boolean 1119 | */ 1120 | public function getVerp() 1121 | { 1122 | return $this->do_verp; 1123 | } 1124 | 1125 | /** 1126 | * Set error messages and codes. 1127 | * @param string $message The error message 1128 | * @param string $detail Further detail on the error 1129 | * @param string $smtp_code An associated SMTP error code 1130 | * @param string $smtp_code_ex Extended SMTP code 1131 | */ 1132 | protected function setError($message, $detail = '', $smtp_code = '', $smtp_code_ex = '') 1133 | { 1134 | $this->error = array( 1135 | 'error' => $message, 1136 | 'detail' => $detail, 1137 | 'smtp_code' => $smtp_code, 1138 | 'smtp_code_ex' => $smtp_code_ex 1139 | ); 1140 | } 1141 | 1142 | /** 1143 | * Set debug output method. 1144 | * @param string|callable $method The name of the mechanism to use for debugging output, or a callable to handle it. 1145 | */ 1146 | public function setDebugOutput($method = 'echo') 1147 | { 1148 | $this->Debugoutput = $method; 1149 | } 1150 | 1151 | /** 1152 | * Get debug output method. 1153 | * @return string 1154 | */ 1155 | public function getDebugOutput() 1156 | { 1157 | return $this->Debugoutput; 1158 | } 1159 | 1160 | /** 1161 | * Set debug output level. 1162 | * @param integer $level 1163 | */ 1164 | public function setDebugLevel($level = 0) 1165 | { 1166 | $this->do_debug = $level; 1167 | } 1168 | 1169 | /** 1170 | * Get debug output level. 1171 | * @return integer 1172 | */ 1173 | public function getDebugLevel() 1174 | { 1175 | return $this->do_debug; 1176 | } 1177 | 1178 | /** 1179 | * Set SMTP timeout. 1180 | * @param integer $timeout 1181 | */ 1182 | public function setTimeout($timeout = 0) 1183 | { 1184 | $this->Timeout = $timeout; 1185 | } 1186 | 1187 | /** 1188 | * Get SMTP timeout. 1189 | * @return integer 1190 | */ 1191 | public function getTimeout() 1192 | { 1193 | return $this->Timeout; 1194 | } 1195 | 1196 | /** 1197 | * Reports an error number and string. 1198 | * @param integer $errno The error number returned by PHP. 1199 | * @param string $errmsg The error message returned by PHP. 1200 | */ 1201 | protected function errorHandler($errno, $errmsg) 1202 | { 1203 | $notice = 'Connection: Failed to connect to server.'; 1204 | $this->setError( 1205 | $notice, 1206 | $errno, 1207 | $errmsg 1208 | ); 1209 | $this->edebug( 1210 | $notice . ' Error number ' . $errno . '. "Error notice: ' . $errmsg, 1211 | self::DEBUG_CONNECTION 1212 | ); 1213 | } 1214 | } 1215 | -------------------------------------------------------------------------------- /libs/phpmailer/PHPMailerAutoload.php: -------------------------------------------------------------------------------- 1 | 8 | * @author Jim Jagielski (jimjag) 9 | * @author Andy Prevost (codeworxtech) 10 | * @author Brent R. Matzelle (original founder) 11 | * @copyright 2012 - 2014 Marcus Bointon 12 | * @copyright 2010 - 2012 Jim Jagielski 13 | * @copyright 2004 - 2009 Andy Prevost 14 | * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License 15 | * @note This program is distributed in the hope that it will be useful - WITHOUT 16 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 17 | * FITNESS FOR A PARTICULAR PURPOSE. 18 | */ 19 | 20 | /** 21 | * PHPMailer SPL autoloader. 22 | * @param string $classname The name of the class to load 23 | */ 24 | function PHPMailerAutoload($classname) 25 | { 26 | //Can't use __DIR__ as it's only in PHP 5.3+ 27 | $filename = dirname(__FILE__).DIRECTORY_SEPARATOR.'class.'.strtolower($classname).'.php'; 28 | if (is_readable($filename)) { 29 | require $filename; 30 | } 31 | } 32 | 33 | if (version_compare(PHP_VERSION, '5.1.2', '>=')) { 34 | //SPL autoloading was introduced in PHP 5.1.2 35 | if (version_compare(PHP_VERSION, '5.3.0', '>=')) { 36 | spl_autoload_register('PHPMailerAutoload', true, true); 37 | } else { 38 | spl_autoload_register('PHPMailerAutoload'); 39 | } 40 | } else { 41 | /** 42 | * Fall back to traditional autoload for old PHP versions 43 | * @param string $classname The name of the class to load 44 | */ 45 | function __autoload($classname) 46 | { 47 | PHPMailerAutoload($classname); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /libs/phpmailer/class.pop3.php: -------------------------------------------------------------------------------- 1 | 8 | * @author Jim Jagielski (jimjag) 9 | * @author Andy Prevost (codeworxtech) 10 | * @author Brent R. Matzelle (original founder) 11 | * @copyright 2012 - 2014 Marcus Bointon 12 | * @copyright 2010 - 2012 Jim Jagielski 13 | * @copyright 2004 - 2009 Andy Prevost 14 | * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License 15 | * @note This program is distributed in the hope that it will be useful - WITHOUT 16 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 17 | * FITNESS FOR A PARTICULAR PURPOSE. 18 | */ 19 | 20 | /** 21 | * PHPMailer POP-Before-SMTP Authentication Class. 22 | * Specifically for PHPMailer to use for RFC1939 POP-before-SMTP authentication. 23 | * Does not support APOP. 24 | * @package PHPMailer 25 | * @author Richard Davey (original author) 26 | * @author Marcus Bointon (Synchro/coolbru) 27 | * @author Jim Jagielski (jimjag) 28 | * @author Andy Prevost (codeworxtech) 29 | */ 30 | class POP3 31 | { 32 | /** 33 | * The POP3 PHPMailer Version number. 34 | * @var string 35 | * @access public 36 | */ 37 | public $Version = '5.2.16'; 38 | 39 | /** 40 | * Default POP3 port number. 41 | * @var integer 42 | * @access public 43 | */ 44 | public $POP3_PORT = 110; 45 | 46 | /** 47 | * Default timeout in seconds. 48 | * @var integer 49 | * @access public 50 | */ 51 | public $POP3_TIMEOUT = 30; 52 | 53 | /** 54 | * POP3 Carriage Return + Line Feed. 55 | * @var string 56 | * @access public 57 | * @deprecated Use the constant instead 58 | */ 59 | public $CRLF = "\r\n"; 60 | 61 | /** 62 | * Debug display level. 63 | * Options: 0 = no, 1+ = yes 64 | * @var integer 65 | * @access public 66 | */ 67 | public $do_debug = 0; 68 | 69 | /** 70 | * POP3 mail server hostname. 71 | * @var string 72 | * @access public 73 | */ 74 | public $host; 75 | 76 | /** 77 | * POP3 port number. 78 | * @var integer 79 | * @access public 80 | */ 81 | public $port; 82 | 83 | /** 84 | * POP3 Timeout Value in seconds. 85 | * @var integer 86 | * @access public 87 | */ 88 | public $tval; 89 | 90 | /** 91 | * POP3 username 92 | * @var string 93 | * @access public 94 | */ 95 | public $username; 96 | 97 | /** 98 | * POP3 password. 99 | * @var string 100 | * @access public 101 | */ 102 | public $password; 103 | 104 | /** 105 | * Resource handle for the POP3 connection socket. 106 | * @var resource 107 | * @access protected 108 | */ 109 | protected $pop_conn; 110 | 111 | /** 112 | * Are we connected? 113 | * @var boolean 114 | * @access protected 115 | */ 116 | protected $connected = false; 117 | 118 | /** 119 | * Error container. 120 | * @var array 121 | * @access protected 122 | */ 123 | protected $errors = array(); 124 | 125 | /** 126 | * Line break constant 127 | */ 128 | const CRLF = "\r\n"; 129 | 130 | /** 131 | * Simple static wrapper for all-in-one POP before SMTP 132 | * @param $host 133 | * @param integer|boolean $port The port number to connect to 134 | * @param integer|boolean $timeout The timeout value 135 | * @param string $username 136 | * @param string $password 137 | * @param integer $debug_level 138 | * @return boolean 139 | */ 140 | public static function popBeforeSmtp( 141 | $host, 142 | $port = false, 143 | $timeout = false, 144 | $username = '', 145 | $password = '', 146 | $debug_level = 0 147 | ) { 148 | $pop = new POP3; 149 | return $pop->authorise($host, $port, $timeout, $username, $password, $debug_level); 150 | } 151 | 152 | /** 153 | * Authenticate with a POP3 server. 154 | * A connect, login, disconnect sequence 155 | * appropriate for POP-before SMTP authorisation. 156 | * @access public 157 | * @param string $host The hostname to connect to 158 | * @param integer|boolean $port The port number to connect to 159 | * @param integer|boolean $timeout The timeout value 160 | * @param string $username 161 | * @param string $password 162 | * @param integer $debug_level 163 | * @return boolean 164 | */ 165 | public function authorise($host, $port = false, $timeout = false, $username = '', $password = '', $debug_level = 0) 166 | { 167 | $this->host = $host; 168 | // If no port value provided, use default 169 | if (false === $port) { 170 | $this->port = $this->POP3_PORT; 171 | } else { 172 | $this->port = (integer)$port; 173 | } 174 | // If no timeout value provided, use default 175 | if (false === $timeout) { 176 | $this->tval = $this->POP3_TIMEOUT; 177 | } else { 178 | $this->tval = (integer)$timeout; 179 | } 180 | $this->do_debug = $debug_level; 181 | $this->username = $username; 182 | $this->password = $password; 183 | // Reset the error log 184 | $this->errors = array(); 185 | // connect 186 | $result = $this->connect($this->host, $this->port, $this->tval); 187 | if ($result) { 188 | $login_result = $this->login($this->username, $this->password); 189 | if ($login_result) { 190 | $this->disconnect(); 191 | return true; 192 | } 193 | } 194 | // We need to disconnect regardless of whether the login succeeded 195 | $this->disconnect(); 196 | return false; 197 | } 198 | 199 | /** 200 | * Connect to a POP3 server. 201 | * @access public 202 | * @param string $host 203 | * @param integer|boolean $port 204 | * @param integer $tval 205 | * @return boolean 206 | */ 207 | public function connect($host, $port = false, $tval = 30) 208 | { 209 | // Are we already connected? 210 | if ($this->connected) { 211 | return true; 212 | } 213 | 214 | //On Windows this will raise a PHP Warning error if the hostname doesn't exist. 215 | //Rather than suppress it with @fsockopen, capture it cleanly instead 216 | set_error_handler(array($this, 'catchWarning')); 217 | 218 | if (false === $port) { 219 | $port = $this->POP3_PORT; 220 | } 221 | 222 | // connect to the POP3 server 223 | $this->pop_conn = fsockopen( 224 | $host, // POP3 Host 225 | $port, // Port # 226 | $errno, // Error Number 227 | $errstr, // Error Message 228 | $tval 229 | ); // Timeout (seconds) 230 | // Restore the error handler 231 | restore_error_handler(); 232 | 233 | // Did we connect? 234 | if (false === $this->pop_conn) { 235 | // It would appear not... 236 | $this->setError(array( 237 | 'error' => "Failed to connect to server $host on port $port", 238 | 'errno' => $errno, 239 | 'errstr' => $errstr 240 | )); 241 | return false; 242 | } 243 | 244 | // Increase the stream time-out 245 | stream_set_timeout($this->pop_conn, $tval, 0); 246 | 247 | // Get the POP3 server response 248 | $pop3_response = $this->getResponse(); 249 | // Check for the +OK 250 | if ($this->checkResponse($pop3_response)) { 251 | // The connection is established and the POP3 server is talking 252 | $this->connected = true; 253 | return true; 254 | } 255 | return false; 256 | } 257 | 258 | /** 259 | * Log in to the POP3 server. 260 | * Does not support APOP (RFC 2828, 4949). 261 | * @access public 262 | * @param string $username 263 | * @param string $password 264 | * @return boolean 265 | */ 266 | public function login($username = '', $password = '') 267 | { 268 | if (!$this->connected) { 269 | $this->setError('Not connected to POP3 server'); 270 | } 271 | if (empty($username)) { 272 | $username = $this->username; 273 | } 274 | if (empty($password)) { 275 | $password = $this->password; 276 | } 277 | 278 | // Send the Username 279 | $this->sendString("USER $username" . self::CRLF); 280 | $pop3_response = $this->getResponse(); 281 | if ($this->checkResponse($pop3_response)) { 282 | // Send the Password 283 | $this->sendString("PASS $password" . self::CRLF); 284 | $pop3_response = $this->getResponse(); 285 | if ($this->checkResponse($pop3_response)) { 286 | return true; 287 | } 288 | } 289 | return false; 290 | } 291 | 292 | /** 293 | * Disconnect from the POP3 server. 294 | * @access public 295 | */ 296 | public function disconnect() 297 | { 298 | $this->sendString('QUIT'); 299 | //The QUIT command may cause the daemon to exit, which will kill our connection 300 | //So ignore errors here 301 | try { 302 | @fclose($this->pop_conn); 303 | } catch (Exception $e) { 304 | //Do nothing 305 | }; 306 | } 307 | 308 | /** 309 | * Get a response from the POP3 server. 310 | * $size is the maximum number of bytes to retrieve 311 | * @param integer $size 312 | * @return string 313 | * @access protected 314 | */ 315 | protected function getResponse($size = 128) 316 | { 317 | $response = fgets($this->pop_conn, $size); 318 | if ($this->do_debug >= 1) { 319 | echo "Server -> Client: $response"; 320 | } 321 | return $response; 322 | } 323 | 324 | /** 325 | * Send raw data to the POP3 server. 326 | * @param string $string 327 | * @return integer 328 | * @access protected 329 | */ 330 | protected function sendString($string) 331 | { 332 | if ($this->pop_conn) { 333 | if ($this->do_debug >= 2) { //Show client messages when debug >= 2 334 | echo "Client -> Server: $string"; 335 | } 336 | return fwrite($this->pop_conn, $string, strlen($string)); 337 | } 338 | return 0; 339 | } 340 | 341 | /** 342 | * Checks the POP3 server response. 343 | * Looks for for +OK or -ERR. 344 | * @param string $string 345 | * @return boolean 346 | * @access protected 347 | */ 348 | protected function checkResponse($string) 349 | { 350 | if (substr($string, 0, 3) !== '+OK') { 351 | $this->setError(array( 352 | 'error' => "Server reported an error: $string", 353 | 'errno' => 0, 354 | 'errstr' => '' 355 | )); 356 | return false; 357 | } else { 358 | return true; 359 | } 360 | } 361 | 362 | /** 363 | * Add an error to the internal error store. 364 | * Also display debug output if it's enabled. 365 | * @param $error 366 | * @access protected 367 | */ 368 | protected function setError($error) 369 | { 370 | $this->errors[] = $error; 371 | if ($this->do_debug >= 1) { 372 | echo '
';
373 |             foreach ($this->errors as $error) {
374 |                 print_r($error);
375 |             }
376 |             echo '
'; 377 | } 378 | } 379 | 380 | /** 381 | * Get an array of error messages, if any. 382 | * @return array 383 | */ 384 | public function getErrors() 385 | { 386 | return $this->errors; 387 | } 388 | 389 | /** 390 | * POP3 connection error handler. 391 | * @param integer $errno 392 | * @param string $errstr 393 | * @param string $errfile 394 | * @param integer $errline 395 | * @access protected 396 | */ 397 | protected function catchWarning($errno, $errstr, $errfile, $errline) 398 | { 399 | $this->setError(array( 400 | 'error' => "Connecting to the POP3 server raised a PHP warning: ", 401 | 'errno' => $errno, 402 | 'errstr' => $errstr, 403 | 'errfile' => $errfile, 404 | 'errline' => $errline 405 | )); 406 | } 407 | } 408 | -------------------------------------------------------------------------------- /libs/phpmailer/class.smtp.php: -------------------------------------------------------------------------------- 1 | 8 | * @author Jim Jagielski (jimjag) 9 | * @author Andy Prevost (codeworxtech) 10 | * @author Brent R. Matzelle (original founder) 11 | * @copyright 2014 Marcus Bointon 12 | * @copyright 2010 - 2012 Jim Jagielski 13 | * @copyright 2004 - 2009 Andy Prevost 14 | * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License 15 | * @note This program is distributed in the hope that it will be useful - WITHOUT 16 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 17 | * FITNESS FOR A PARTICULAR PURPOSE. 18 | */ 19 | 20 | /** 21 | * PHPMailer RFC821 SMTP email transport class. 22 | * Implements RFC 821 SMTP commands and provides some utility methods for sending mail to an SMTP server. 23 | * @package PHPMailer 24 | * @author Chris Ryan 25 | * @author Marcus Bointon 26 | */ 27 | class SMTP 28 | { 29 | /** 30 | * The PHPMailer SMTP version number. 31 | * @var string 32 | */ 33 | const VERSION = '5.2.16'; 34 | 35 | /** 36 | * SMTP line break constant. 37 | * @var string 38 | */ 39 | const CRLF = "\r\n"; 40 | 41 | /** 42 | * The SMTP port to use if one is not specified. 43 | * @var integer 44 | */ 45 | const DEFAULT_SMTP_PORT = 25; 46 | 47 | /** 48 | * The maximum line length allowed by RFC 2822 section 2.1.1 49 | * @var integer 50 | */ 51 | const MAX_LINE_LENGTH = 998; 52 | 53 | /** 54 | * Debug level for no output 55 | */ 56 | const DEBUG_OFF = 0; 57 | 58 | /** 59 | * Debug level to show client -> server messages 60 | */ 61 | const DEBUG_CLIENT = 1; 62 | 63 | /** 64 | * Debug level to show client -> server and server -> client messages 65 | */ 66 | const DEBUG_SERVER = 2; 67 | 68 | /** 69 | * Debug level to show connection status, client -> server and server -> client messages 70 | */ 71 | const DEBUG_CONNECTION = 3; 72 | 73 | /** 74 | * Debug level to show all messages 75 | */ 76 | const DEBUG_LOWLEVEL = 4; 77 | 78 | /** 79 | * The PHPMailer SMTP Version number. 80 | * @var string 81 | * @deprecated Use the `VERSION` constant instead 82 | * @see SMTP::VERSION 83 | */ 84 | public $Version = '5.2.16'; 85 | 86 | /** 87 | * SMTP server port number. 88 | * @var integer 89 | * @deprecated This is only ever used as a default value, so use the `DEFAULT_SMTP_PORT` constant instead 90 | * @see SMTP::DEFAULT_SMTP_PORT 91 | */ 92 | public $SMTP_PORT = 25; 93 | 94 | /** 95 | * SMTP reply line ending. 96 | * @var string 97 | * @deprecated Use the `CRLF` constant instead 98 | * @see SMTP::CRLF 99 | */ 100 | public $CRLF = "\r\n"; 101 | 102 | /** 103 | * Debug output level. 104 | * Options: 105 | * * self::DEBUG_OFF (`0`) No debug output, default 106 | * * self::DEBUG_CLIENT (`1`) Client commands 107 | * * self::DEBUG_SERVER (`2`) Client commands and server responses 108 | * * self::DEBUG_CONNECTION (`3`) As DEBUG_SERVER plus connection status 109 | * * self::DEBUG_LOWLEVEL (`4`) Low-level data output, all messages 110 | * @var integer 111 | */ 112 | public $do_debug = self::DEBUG_OFF; 113 | 114 | /** 115 | * How to handle debug output. 116 | * Options: 117 | * * `echo` Output plain-text as-is, appropriate for CLI 118 | * * `html` Output escaped, line breaks converted to `
`, appropriate for browser output 119 | * * `error_log` Output to error log as configured in php.ini 120 | * 121 | * Alternatively, you can provide a callable expecting two params: a message string and the debug level: 122 | * 123 | * $smtp->Debugoutput = function($str, $level) {echo "debug level $level; message: $str";}; 124 | * 125 | * @var string|callable 126 | */ 127 | public $Debugoutput = 'echo'; 128 | 129 | /** 130 | * Whether to use VERP. 131 | * @link http://en.wikipedia.org/wiki/Variable_envelope_return_path 132 | * @link http://www.postfix.org/VERP_README.html Info on VERP 133 | * @var boolean 134 | */ 135 | public $do_verp = false; 136 | 137 | /** 138 | * The timeout value for connection, in seconds. 139 | * Default of 5 minutes (300sec) is from RFC2821 section 4.5.3.2 140 | * This needs to be quite high to function correctly with hosts using greetdelay as an anti-spam measure. 141 | * @link http://tools.ietf.org/html/rfc2821#section-4.5.3.2 142 | * @var integer 143 | */ 144 | public $Timeout = 300; 145 | 146 | /** 147 | * How long to wait for commands to complete, in seconds. 148 | * Default of 5 minutes (300sec) is from RFC2821 section 4.5.3.2 149 | * @var integer 150 | */ 151 | public $Timelimit = 300; 152 | 153 | /** 154 | * The socket for the server connection. 155 | * @var resource 156 | */ 157 | protected $smtp_conn; 158 | 159 | /** 160 | * Error information, if any, for the last SMTP command. 161 | * @var array 162 | */ 163 | protected $error = array( 164 | 'error' => '', 165 | 'detail' => '', 166 | 'smtp_code' => '', 167 | 'smtp_code_ex' => '' 168 | ); 169 | 170 | /** 171 | * The reply the server sent to us for HELO. 172 | * If null, no HELO string has yet been received. 173 | * @var string|null 174 | */ 175 | protected $helo_rply = null; 176 | 177 | /** 178 | * The set of SMTP extensions sent in reply to EHLO command. 179 | * Indexes of the array are extension names. 180 | * Value at index 'HELO' or 'EHLO' (according to command that was sent) 181 | * represents the server name. In case of HELO it is the only element of the array. 182 | * Other values can be boolean TRUE or an array containing extension options. 183 | * If null, no HELO/EHLO string has yet been received. 184 | * @var array|null 185 | */ 186 | protected $server_caps = null; 187 | 188 | /** 189 | * The most recent reply received from the server. 190 | * @var string 191 | */ 192 | protected $last_reply = ''; 193 | 194 | /** 195 | * Output debugging info via a user-selected method. 196 | * @see SMTP::$Debugoutput 197 | * @see SMTP::$do_debug 198 | * @param string $str Debug string to output 199 | * @param integer $level The debug level of this message; see DEBUG_* constants 200 | * @return void 201 | */ 202 | protected function edebug($str, $level = 0) 203 | { 204 | if ($level > $this->do_debug) { 205 | return; 206 | } 207 | //Avoid clash with built-in function names 208 | if (!in_array($this->Debugoutput, array('error_log', 'html', 'echo')) and is_callable($this->Debugoutput)) { 209 | call_user_func($this->Debugoutput, $str, $level); 210 | return; 211 | } 212 | switch ($this->Debugoutput) { 213 | case 'error_log': 214 | //Don't output, just log 215 | error_log($str); 216 | break; 217 | case 'html': 218 | //Cleans up output a bit for a better looking, HTML-safe output 219 | echo htmlentities( 220 | preg_replace('/[\r\n]+/', '', $str), 221 | ENT_QUOTES, 222 | 'UTF-8' 223 | ) 224 | . "
\n"; 225 | break; 226 | case 'echo': 227 | default: 228 | //Normalize line breaks 229 | $str = preg_replace('/(\r\n|\r|\n)/ms', "\n", $str); 230 | echo gmdate('Y-m-d H:i:s') . "\t" . str_replace( 231 | "\n", 232 | "\n \t ", 233 | trim($str) 234 | )."\n"; 235 | } 236 | } 237 | 238 | /** 239 | * Connect to an SMTP server. 240 | * @param string $host SMTP server IP or host name 241 | * @param integer $port The port number to connect to 242 | * @param integer $timeout How long to wait for the connection to open 243 | * @param array $options An array of options for stream_context_create() 244 | * @access public 245 | * @return boolean 246 | */ 247 | public function connect($host, $port = null, $timeout = 30, $options = array()) 248 | { 249 | static $streamok; 250 | //This is enabled by default since 5.0.0 but some providers disable it 251 | //Check this once and cache the result 252 | if (is_null($streamok)) { 253 | $streamok = function_exists('stream_socket_client'); 254 | } 255 | // Clear errors to avoid confusion 256 | $this->setError(''); 257 | // Make sure we are __not__ connected 258 | if ($this->connected()) { 259 | // Already connected, generate error 260 | $this->setError('Already connected to a server'); 261 | return false; 262 | } 263 | if (empty($port)) { 264 | $port = self::DEFAULT_SMTP_PORT; 265 | } 266 | // Connect to the SMTP server 267 | $this->edebug( 268 | "Connection: opening to $host:$port, timeout=$timeout, options=".var_export($options, true), 269 | self::DEBUG_CONNECTION 270 | ); 271 | $errno = 0; 272 | $errstr = ''; 273 | if ($streamok) { 274 | $socket_context = stream_context_create($options); 275 | set_error_handler(array($this, 'errorHandler')); 276 | $this->smtp_conn = stream_socket_client( 277 | $host . ":" . $port, 278 | $errno, 279 | $errstr, 280 | $timeout, 281 | STREAM_CLIENT_CONNECT, 282 | $socket_context 283 | ); 284 | restore_error_handler(); 285 | } else { 286 | //Fall back to fsockopen which should work in more places, but is missing some features 287 | $this->edebug( 288 | "Connection: stream_socket_client not available, falling back to fsockopen", 289 | self::DEBUG_CONNECTION 290 | ); 291 | set_error_handler(array($this, 'errorHandler')); 292 | $this->smtp_conn = fsockopen( 293 | $host, 294 | $port, 295 | $errno, 296 | $errstr, 297 | $timeout 298 | ); 299 | restore_error_handler(); 300 | } 301 | // Verify we connected properly 302 | if (!is_resource($this->smtp_conn)) { 303 | $this->setError( 304 | 'Failed to connect to server', 305 | $errno, 306 | $errstr 307 | ); 308 | $this->edebug( 309 | 'SMTP ERROR: ' . $this->error['error'] 310 | . ": $errstr ($errno)", 311 | self::DEBUG_CLIENT 312 | ); 313 | return false; 314 | } 315 | $this->edebug('Connection: opened', self::DEBUG_CONNECTION); 316 | // SMTP server can take longer to respond, give longer timeout for first read 317 | // Windows does not have support for this timeout function 318 | if (substr(PHP_OS, 0, 3) != 'WIN') { 319 | $max = ini_get('max_execution_time'); 320 | // Don't bother if unlimited 321 | if ($max != 0 && $timeout > $max) { 322 | @set_time_limit($timeout); 323 | } 324 | stream_set_timeout($this->smtp_conn, $timeout, 0); 325 | } 326 | // Get any announcement 327 | $announce = $this->get_lines(); 328 | $this->edebug('SERVER -> CLIENT: ' . $announce, self::DEBUG_SERVER); 329 | return true; 330 | } 331 | 332 | /** 333 | * Initiate a TLS (encrypted) session. 334 | * @access public 335 | * @return boolean 336 | */ 337 | public function startTLS() 338 | { 339 | if (!$this->sendCommand('STARTTLS', 'STARTTLS', 220)) { 340 | return false; 341 | } 342 | 343 | //Allow the best TLS version(s) we can 344 | $crypto_method = STREAM_CRYPTO_METHOD_TLS_CLIENT; 345 | 346 | //PHP 5.6.7 dropped inclusion of TLS 1.1 and 1.2 in STREAM_CRYPTO_METHOD_TLS_CLIENT 347 | //so add them back in manually if we can 348 | if (defined('STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT')) { 349 | $crypto_method |= STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT; 350 | $crypto_method |= STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT; 351 | } 352 | 353 | // Begin encrypted connection 354 | if (!stream_socket_enable_crypto( 355 | $this->smtp_conn, 356 | true, 357 | $crypto_method 358 | )) { 359 | return false; 360 | } 361 | return true; 362 | } 363 | 364 | /** 365 | * Perform SMTP authentication. 366 | * Must be run after hello(). 367 | * @see hello() 368 | * @param string $username The user name 369 | * @param string $password The password 370 | * @param string $authtype The auth type (PLAIN, LOGIN, NTLM, CRAM-MD5, XOAUTH2) 371 | * @param string $realm The auth realm for NTLM 372 | * @param string $workstation The auth workstation for NTLM 373 | * @param null|OAuth $OAuth An optional OAuth instance (@see PHPMailerOAuth) 374 | * @return bool True if successfully authenticated.* @access public 375 | */ 376 | public function authenticate( 377 | $username, 378 | $password, 379 | $authtype = null, 380 | $realm = '', 381 | $workstation = '', 382 | $OAuth = null 383 | ) { 384 | if (!$this->server_caps) { 385 | $this->setError('Authentication is not allowed before HELO/EHLO'); 386 | return false; 387 | } 388 | 389 | if (array_key_exists('EHLO', $this->server_caps)) { 390 | // SMTP extensions are available. Let's try to find a proper authentication method 391 | 392 | if (!array_key_exists('AUTH', $this->server_caps)) { 393 | $this->setError('Authentication is not allowed at this stage'); 394 | // 'at this stage' means that auth may be allowed after the stage changes 395 | // e.g. after STARTTLS 396 | return false; 397 | } 398 | 399 | self::edebug('Auth method requested: ' . ($authtype ? $authtype : 'UNKNOWN'), self::DEBUG_LOWLEVEL); 400 | self::edebug( 401 | 'Auth methods available on the server: ' . implode(',', $this->server_caps['AUTH']), 402 | self::DEBUG_LOWLEVEL 403 | ); 404 | 405 | if (empty($authtype)) { 406 | foreach (array('CRAM-MD5', 'LOGIN', 'PLAIN', 'NTLM', 'XOAUTH2') as $method) { 407 | if (in_array($method, $this->server_caps['AUTH'])) { 408 | $authtype = $method; 409 | break; 410 | } 411 | } 412 | if (empty($authtype)) { 413 | $this->setError('No supported authentication methods found'); 414 | return false; 415 | } 416 | self::edebug('Auth method selected: '.$authtype, self::DEBUG_LOWLEVEL); 417 | } 418 | 419 | if (!in_array($authtype, $this->server_caps['AUTH'])) { 420 | $this->setError("The requested authentication method \"$authtype\" is not supported by the server"); 421 | return false; 422 | } 423 | } elseif (empty($authtype)) { 424 | $authtype = 'LOGIN'; 425 | } 426 | switch ($authtype) { 427 | case 'PLAIN': 428 | // Start authentication 429 | if (!$this->sendCommand('AUTH', 'AUTH PLAIN', 334)) { 430 | return false; 431 | } 432 | // Send encoded username and password 433 | if (!$this->sendCommand( 434 | 'User & Password', 435 | base64_encode("\0" . $username . "\0" . $password), 436 | 235 437 | ) 438 | ) { 439 | return false; 440 | } 441 | break; 442 | case 'LOGIN': 443 | // Start authentication 444 | if (!$this->sendCommand('AUTH', 'AUTH LOGIN', 334)) { 445 | return false; 446 | } 447 | if (!$this->sendCommand("Username", base64_encode($username), 334)) { 448 | return false; 449 | } 450 | if (!$this->sendCommand("Password", base64_encode($password), 235)) { 451 | return false; 452 | } 453 | break; 454 | case 'XOAUTH2': 455 | //If the OAuth Instance is not set. Can be a case when PHPMailer is used 456 | //instead of PHPMailerOAuth 457 | if (is_null($OAuth)) { 458 | return false; 459 | } 460 | $oauth = $OAuth->getOauth64(); 461 | 462 | // Start authentication 463 | if (!$this->sendCommand('AUTH', 'AUTH XOAUTH2 ' . $oauth, 235)) { 464 | return false; 465 | } 466 | break; 467 | case 'NTLM': 468 | /* 469 | * ntlm_sasl_client.php 470 | * Bundled with Permission 471 | * 472 | * How to telnet in windows: 473 | * http://technet.microsoft.com/en-us/library/aa995718%28EXCHG.65%29.aspx 474 | * PROTOCOL Docs http://curl.haxx.se/rfc/ntlm.html#ntlmSmtpAuthentication 475 | */ 476 | require_once 'extras/ntlm_sasl_client.php'; 477 | $temp = new stdClass; 478 | $ntlm_client = new ntlm_sasl_client_class; 479 | //Check that functions are available 480 | if (!$ntlm_client->initialize($temp)) { 481 | $this->setError($temp->error); 482 | $this->edebug( 483 | 'You need to enable some modules in your php.ini file: ' 484 | . $this->error['error'], 485 | self::DEBUG_CLIENT 486 | ); 487 | return false; 488 | } 489 | //msg1 490 | $msg1 = $ntlm_client->typeMsg1($realm, $workstation); //msg1 491 | 492 | if (!$this->sendCommand( 493 | 'AUTH NTLM', 494 | 'AUTH NTLM ' . base64_encode($msg1), 495 | 334 496 | ) 497 | ) { 498 | return false; 499 | } 500 | //Though 0 based, there is a white space after the 3 digit number 501 | //msg2 502 | $challenge = substr($this->last_reply, 3); 503 | $challenge = base64_decode($challenge); 504 | $ntlm_res = $ntlm_client->NTLMResponse( 505 | substr($challenge, 24, 8), 506 | $password 507 | ); 508 | //msg3 509 | $msg3 = $ntlm_client->typeMsg3( 510 | $ntlm_res, 511 | $username, 512 | $realm, 513 | $workstation 514 | ); 515 | // send encoded username 516 | return $this->sendCommand('Username', base64_encode($msg3), 235); 517 | case 'CRAM-MD5': 518 | // Start authentication 519 | if (!$this->sendCommand('AUTH CRAM-MD5', 'AUTH CRAM-MD5', 334)) { 520 | return false; 521 | } 522 | // Get the challenge 523 | $challenge = base64_decode(substr($this->last_reply, 4)); 524 | 525 | // Build the response 526 | $response = $username . ' ' . $this->hmac($challenge, $password); 527 | 528 | // send encoded credentials 529 | return $this->sendCommand('Username', base64_encode($response), 235); 530 | default: 531 | $this->setError("Authentication method \"$authtype\" is not supported"); 532 | return false; 533 | } 534 | return true; 535 | } 536 | 537 | /** 538 | * Calculate an MD5 HMAC hash. 539 | * Works like hash_hmac('md5', $data, $key) 540 | * in case that function is not available 541 | * @param string $data The data to hash 542 | * @param string $key The key to hash with 543 | * @access protected 544 | * @return string 545 | */ 546 | protected function hmac($data, $key) 547 | { 548 | if (function_exists('hash_hmac')) { 549 | return hash_hmac('md5', $data, $key); 550 | } 551 | 552 | // The following borrowed from 553 | // http://php.net/manual/en/function.mhash.php#27225 554 | 555 | // RFC 2104 HMAC implementation for php. 556 | // Creates an md5 HMAC. 557 | // Eliminates the need to install mhash to compute a HMAC 558 | // by Lance Rushing 559 | 560 | $bytelen = 64; // byte length for md5 561 | if (strlen($key) > $bytelen) { 562 | $key = pack('H*', md5($key)); 563 | } 564 | $key = str_pad($key, $bytelen, chr(0x00)); 565 | $ipad = str_pad('', $bytelen, chr(0x36)); 566 | $opad = str_pad('', $bytelen, chr(0x5c)); 567 | $k_ipad = $key ^ $ipad; 568 | $k_opad = $key ^ $opad; 569 | 570 | return md5($k_opad . pack('H*', md5($k_ipad . $data))); 571 | } 572 | 573 | /** 574 | * Check connection state. 575 | * @access public 576 | * @return boolean True if connected. 577 | */ 578 | public function connected() 579 | { 580 | if (is_resource($this->smtp_conn)) { 581 | $sock_status = stream_get_meta_data($this->smtp_conn); 582 | if ($sock_status['eof']) { 583 | // The socket is valid but we are not connected 584 | $this->edebug( 585 | 'SMTP NOTICE: EOF caught while checking if connected', 586 | self::DEBUG_CLIENT 587 | ); 588 | $this->close(); 589 | return false; 590 | } 591 | return true; // everything looks good 592 | } 593 | return false; 594 | } 595 | 596 | /** 597 | * Close the socket and clean up the state of the class. 598 | * Don't use this function without first trying to use QUIT. 599 | * @see quit() 600 | * @access public 601 | * @return void 602 | */ 603 | public function close() 604 | { 605 | $this->setError(''); 606 | $this->server_caps = null; 607 | $this->helo_rply = null; 608 | if (is_resource($this->smtp_conn)) { 609 | // close the connection and cleanup 610 | fclose($this->smtp_conn); 611 | $this->smtp_conn = null; //Makes for cleaner serialization 612 | $this->edebug('Connection: closed', self::DEBUG_CONNECTION); 613 | } 614 | } 615 | 616 | /** 617 | * Send an SMTP DATA command. 618 | * Issues a data command and sends the msg_data to the server, 619 | * finializing the mail transaction. $msg_data is the message 620 | * that is to be send with the headers. Each header needs to be 621 | * on a single line followed by a with the message headers 622 | * and the message body being separated by and additional . 623 | * Implements rfc 821: DATA 624 | * @param string $msg_data Message data to send 625 | * @access public 626 | * @return boolean 627 | */ 628 | public function data($msg_data) 629 | { 630 | //This will use the standard timelimit 631 | if (!$this->sendCommand('DATA', 'DATA', 354)) { 632 | return false; 633 | } 634 | 635 | /* The server is ready to accept data! 636 | * According to rfc821 we should not send more than 1000 characters on a single line (including the CRLF) 637 | * so we will break the data up into lines by \r and/or \n then if needed we will break each of those into 638 | * smaller lines to fit within the limit. 639 | * We will also look for lines that start with a '.' and prepend an additional '.'. 640 | * NOTE: this does not count towards line-length limit. 641 | */ 642 | 643 | // Normalize line breaks before exploding 644 | $lines = explode("\n", str_replace(array("\r\n", "\r"), "\n", $msg_data)); 645 | 646 | /* To distinguish between a complete RFC822 message and a plain message body, we check if the first field 647 | * of the first line (':' separated) does not contain a space then it _should_ be a header and we will 648 | * process all lines before a blank line as headers. 649 | */ 650 | 651 | $field = substr($lines[0], 0, strpos($lines[0], ':')); 652 | $in_headers = false; 653 | if (!empty($field) && strpos($field, ' ') === false) { 654 | $in_headers = true; 655 | } 656 | 657 | foreach ($lines as $line) { 658 | $lines_out = array(); 659 | if ($in_headers and $line == '') { 660 | $in_headers = false; 661 | } 662 | //Break this line up into several smaller lines if it's too long 663 | //Micro-optimisation: isset($str[$len]) is faster than (strlen($str) > $len), 664 | while (isset($line[self::MAX_LINE_LENGTH])) { 665 | //Working backwards, try to find a space within the last MAX_LINE_LENGTH chars of the line to break on 666 | //so as to avoid breaking in the middle of a word 667 | $pos = strrpos(substr($line, 0, self::MAX_LINE_LENGTH), ' '); 668 | //Deliberately matches both false and 0 669 | if (!$pos) { 670 | //No nice break found, add a hard break 671 | $pos = self::MAX_LINE_LENGTH - 1; 672 | $lines_out[] = substr($line, 0, $pos); 673 | $line = substr($line, $pos); 674 | } else { 675 | //Break at the found point 676 | $lines_out[] = substr($line, 0, $pos); 677 | //Move along by the amount we dealt with 678 | $line = substr($line, $pos + 1); 679 | } 680 | //If processing headers add a LWSP-char to the front of new line RFC822 section 3.1.1 681 | if ($in_headers) { 682 | $line = "\t" . $line; 683 | } 684 | } 685 | $lines_out[] = $line; 686 | 687 | //Send the lines to the server 688 | foreach ($lines_out as $line_out) { 689 | //RFC2821 section 4.5.2 690 | if (!empty($line_out) and $line_out[0] == '.') { 691 | $line_out = '.' . $line_out; 692 | } 693 | $this->client_send($line_out . self::CRLF); 694 | } 695 | } 696 | 697 | //Message data has been sent, complete the command 698 | //Increase timelimit for end of DATA command 699 | $savetimelimit = $this->Timelimit; 700 | $this->Timelimit = $this->Timelimit * 2; 701 | $result = $this->sendCommand('DATA END', '.', 250); 702 | //Restore timelimit 703 | $this->Timelimit = $savetimelimit; 704 | return $result; 705 | } 706 | 707 | /** 708 | * Send an SMTP HELO or EHLO command. 709 | * Used to identify the sending server to the receiving server. 710 | * This makes sure that client and server are in a known state. 711 | * Implements RFC 821: HELO 712 | * and RFC 2821 EHLO. 713 | * @param string $host The host name or IP to connect to 714 | * @access public 715 | * @return boolean 716 | */ 717 | public function hello($host = '') 718 | { 719 | //Try extended hello first (RFC 2821) 720 | return (boolean)($this->sendHello('EHLO', $host) or $this->sendHello('HELO', $host)); 721 | } 722 | 723 | /** 724 | * Send an SMTP HELO or EHLO command. 725 | * Low-level implementation used by hello() 726 | * @see hello() 727 | * @param string $hello The HELO string 728 | * @param string $host The hostname to say we are 729 | * @access protected 730 | * @return boolean 731 | */ 732 | protected function sendHello($hello, $host) 733 | { 734 | $noerror = $this->sendCommand($hello, $hello . ' ' . $host, 250); 735 | $this->helo_rply = $this->last_reply; 736 | if ($noerror) { 737 | $this->parseHelloFields($hello); 738 | } else { 739 | $this->server_caps = null; 740 | } 741 | return $noerror; 742 | } 743 | 744 | /** 745 | * Parse a reply to HELO/EHLO command to discover server extensions. 746 | * In case of HELO, the only parameter that can be discovered is a server name. 747 | * @access protected 748 | * @param string $type - 'HELO' or 'EHLO' 749 | */ 750 | protected function parseHelloFields($type) 751 | { 752 | $this->server_caps = array(); 753 | $lines = explode("\n", $this->helo_rply); 754 | 755 | foreach ($lines as $n => $s) { 756 | //First 4 chars contain response code followed by - or space 757 | $s = trim(substr($s, 4)); 758 | if (empty($s)) { 759 | continue; 760 | } 761 | $fields = explode(' ', $s); 762 | if (!empty($fields)) { 763 | if (!$n) { 764 | $name = $type; 765 | $fields = $fields[0]; 766 | } else { 767 | $name = array_shift($fields); 768 | switch ($name) { 769 | case 'SIZE': 770 | $fields = ($fields ? $fields[0] : 0); 771 | break; 772 | case 'AUTH': 773 | if (!is_array($fields)) { 774 | $fields = array(); 775 | } 776 | break; 777 | default: 778 | $fields = true; 779 | } 780 | } 781 | $this->server_caps[$name] = $fields; 782 | } 783 | } 784 | } 785 | 786 | /** 787 | * Send an SMTP MAIL command. 788 | * Starts a mail transaction from the email address specified in 789 | * $from. Returns true if successful or false otherwise. If True 790 | * the mail transaction is started and then one or more recipient 791 | * commands may be called followed by a data command. 792 | * Implements rfc 821: MAIL FROM: 793 | * @param string $from Source address of this message 794 | * @access public 795 | * @return boolean 796 | */ 797 | public function mail($from) 798 | { 799 | $useVerp = ($this->do_verp ? ' XVERP' : ''); 800 | return $this->sendCommand( 801 | 'MAIL FROM', 802 | 'MAIL FROM:<' . $from . '>' . $useVerp, 803 | 250 804 | ); 805 | } 806 | 807 | /** 808 | * Send an SMTP QUIT command. 809 | * Closes the socket if there is no error or the $close_on_error argument is true. 810 | * Implements from rfc 821: QUIT 811 | * @param boolean $close_on_error Should the connection close if an error occurs? 812 | * @access public 813 | * @return boolean 814 | */ 815 | public function quit($close_on_error = true) 816 | { 817 | $noerror = $this->sendCommand('QUIT', 'QUIT', 221); 818 | $err = $this->error; //Save any error 819 | if ($noerror or $close_on_error) { 820 | $this->close(); 821 | $this->error = $err; //Restore any error from the quit command 822 | } 823 | return $noerror; 824 | } 825 | 826 | /** 827 | * Send an SMTP RCPT command. 828 | * Sets the TO argument to $toaddr. 829 | * Returns true if the recipient was accepted false if it was rejected. 830 | * Implements from rfc 821: RCPT TO: 831 | * @param string $address The address the message is being sent to 832 | * @access public 833 | * @return boolean 834 | */ 835 | public function recipient($address) 836 | { 837 | return $this->sendCommand( 838 | 'RCPT TO', 839 | 'RCPT TO:<' . $address . '>', 840 | array(250, 251) 841 | ); 842 | } 843 | 844 | /** 845 | * Send an SMTP RSET command. 846 | * Abort any transaction that is currently in progress. 847 | * Implements rfc 821: RSET 848 | * @access public 849 | * @return boolean True on success. 850 | */ 851 | public function reset() 852 | { 853 | return $this->sendCommand('RSET', 'RSET', 250); 854 | } 855 | 856 | /** 857 | * Send a command to an SMTP server and check its return code. 858 | * @param string $command The command name - not sent to the server 859 | * @param string $commandstring The actual command to send 860 | * @param integer|array $expect One or more expected integer success codes 861 | * @access protected 862 | * @return boolean True on success. 863 | */ 864 | protected function sendCommand($command, $commandstring, $expect) 865 | { 866 | if (!$this->connected()) { 867 | $this->setError("Called $command without being connected"); 868 | return false; 869 | } 870 | //Reject line breaks in all commands 871 | if (strpos($commandstring, "\n") !== false or strpos($commandstring, "\r") !== false) { 872 | $this->setError("Command '$command' contained line breaks"); 873 | return false; 874 | } 875 | $this->client_send($commandstring . self::CRLF); 876 | 877 | $this->last_reply = $this->get_lines(); 878 | // Fetch SMTP code and possible error code explanation 879 | $matches = array(); 880 | if (preg_match("/^([0-9]{3})[ -](?:([0-9]\\.[0-9]\\.[0-9]) )?/", $this->last_reply, $matches)) { 881 | $code = $matches[1]; 882 | $code_ex = (count($matches) > 2 ? $matches[2] : null); 883 | // Cut off error code from each response line 884 | $detail = preg_replace( 885 | "/{$code}[ -]".($code_ex ? str_replace('.', '\\.', $code_ex).' ' : '')."/m", 886 | '', 887 | $this->last_reply 888 | ); 889 | } else { 890 | // Fall back to simple parsing if regex fails 891 | $code = substr($this->last_reply, 0, 3); 892 | $code_ex = null; 893 | $detail = substr($this->last_reply, 4); 894 | } 895 | 896 | $this->edebug('SERVER -> CLIENT: ' . $this->last_reply, self::DEBUG_SERVER); 897 | 898 | if (!in_array($code, (array)$expect)) { 899 | $this->setError( 900 | "$command command failed", 901 | $detail, 902 | $code, 903 | $code_ex 904 | ); 905 | $this->edebug( 906 | 'SMTP ERROR: ' . $this->error['error'] . ': ' . $this->last_reply, 907 | self::DEBUG_CLIENT 908 | ); 909 | return false; 910 | } 911 | 912 | $this->setError(''); 913 | return true; 914 | } 915 | 916 | /** 917 | * Send an SMTP SAML command. 918 | * Starts a mail transaction from the email address specified in $from. 919 | * Returns true if successful or false otherwise. If True 920 | * the mail transaction is started and then one or more recipient 921 | * commands may be called followed by a data command. This command 922 | * will send the message to the users terminal if they are logged 923 | * in and send them an email. 924 | * Implements rfc 821: SAML FROM: 925 | * @param string $from The address the message is from 926 | * @access public 927 | * @return boolean 928 | */ 929 | public function sendAndMail($from) 930 | { 931 | return $this->sendCommand('SAML', "SAML FROM:$from", 250); 932 | } 933 | 934 | /** 935 | * Send an SMTP VRFY command. 936 | * @param string $name The name to verify 937 | * @access public 938 | * @return boolean 939 | */ 940 | public function verify($name) 941 | { 942 | return $this->sendCommand('VRFY', "VRFY $name", array(250, 251)); 943 | } 944 | 945 | /** 946 | * Send an SMTP NOOP command. 947 | * Used to keep keep-alives alive, doesn't actually do anything 948 | * @access public 949 | * @return boolean 950 | */ 951 | public function noop() 952 | { 953 | return $this->sendCommand('NOOP', 'NOOP', 250); 954 | } 955 | 956 | /** 957 | * Send an SMTP TURN command. 958 | * This is an optional command for SMTP that this class does not support. 959 | * This method is here to make the RFC821 Definition complete for this class 960 | * and _may_ be implemented in future 961 | * Implements from rfc 821: TURN 962 | * @access public 963 | * @return boolean 964 | */ 965 | public function turn() 966 | { 967 | $this->setError('The SMTP TURN command is not implemented'); 968 | $this->edebug('SMTP NOTICE: ' . $this->error['error'], self::DEBUG_CLIENT); 969 | return false; 970 | } 971 | 972 | /** 973 | * Send raw data to the server. 974 | * @param string $data The data to send 975 | * @access public 976 | * @return integer|boolean The number of bytes sent to the server or false on error 977 | */ 978 | public function client_send($data) 979 | { 980 | $this->edebug("CLIENT -> SERVER: $data", self::DEBUG_CLIENT); 981 | return fwrite($this->smtp_conn, $data); 982 | } 983 | 984 | /** 985 | * Get the latest error. 986 | * @access public 987 | * @return array 988 | */ 989 | public function getError() 990 | { 991 | return $this->error; 992 | } 993 | 994 | /** 995 | * Get SMTP extensions available on the server 996 | * @access public 997 | * @return array|null 998 | */ 999 | public function getServerExtList() 1000 | { 1001 | return $this->server_caps; 1002 | } 1003 | 1004 | /** 1005 | * A multipurpose method 1006 | * The method works in three ways, dependent on argument value and current state 1007 | * 1. HELO/EHLO was not sent - returns null and set up $this->error 1008 | * 2. HELO was sent 1009 | * $name = 'HELO': returns server name 1010 | * $name = 'EHLO': returns boolean false 1011 | * $name = any string: returns null and set up $this->error 1012 | * 3. EHLO was sent 1013 | * $name = 'HELO'|'EHLO': returns server name 1014 | * $name = any string: if extension $name exists, returns boolean True 1015 | * or its options. Otherwise returns boolean False 1016 | * In other words, one can use this method to detect 3 conditions: 1017 | * - null returned: handshake was not or we don't know about ext (refer to $this->error) 1018 | * - false returned: the requested feature exactly not exists 1019 | * - positive value returned: the requested feature exists 1020 | * @param string $name Name of SMTP extension or 'HELO'|'EHLO' 1021 | * @return mixed 1022 | */ 1023 | public function getServerExt($name) 1024 | { 1025 | if (!$this->server_caps) { 1026 | $this->setError('No HELO/EHLO was sent'); 1027 | return null; 1028 | } 1029 | 1030 | // the tight logic knot ;) 1031 | if (!array_key_exists($name, $this->server_caps)) { 1032 | if ($name == 'HELO') { 1033 | return $this->server_caps['EHLO']; 1034 | } 1035 | if ($name == 'EHLO' || array_key_exists('EHLO', $this->server_caps)) { 1036 | return false; 1037 | } 1038 | $this->setError('HELO handshake was used. Client knows nothing about server extensions'); 1039 | return null; 1040 | } 1041 | 1042 | return $this->server_caps[$name]; 1043 | } 1044 | 1045 | /** 1046 | * Get the last reply from the server. 1047 | * @access public 1048 | * @return string 1049 | */ 1050 | public function getLastReply() 1051 | { 1052 | return $this->last_reply; 1053 | } 1054 | 1055 | /** 1056 | * Read the SMTP server's response. 1057 | * Either before eof or socket timeout occurs on the operation. 1058 | * With SMTP we can tell if we have more lines to read if the 1059 | * 4th character is '-' symbol. If it is a space then we don't 1060 | * need to read anything else. 1061 | * @access protected 1062 | * @return string 1063 | */ 1064 | protected function get_lines() 1065 | { 1066 | // If the connection is bad, give up straight away 1067 | if (!is_resource($this->smtp_conn)) { 1068 | return ''; 1069 | } 1070 | $data = ''; 1071 | $endtime = 0; 1072 | stream_set_timeout($this->smtp_conn, $this->Timeout); 1073 | if ($this->Timelimit > 0) { 1074 | $endtime = time() + $this->Timelimit; 1075 | } 1076 | while (is_resource($this->smtp_conn) && !feof($this->smtp_conn)) { 1077 | $str = @fgets($this->smtp_conn, 515); 1078 | $this->edebug("SMTP -> get_lines(): \$data is \"$data\"", self::DEBUG_LOWLEVEL); 1079 | $this->edebug("SMTP -> get_lines(): \$str is \"$str\"", self::DEBUG_LOWLEVEL); 1080 | $data .= $str; 1081 | // If 4th character is a space, we are done reading, break the loop, micro-optimisation over strlen 1082 | if ((isset($str[3]) and $str[3] == ' ')) { 1083 | break; 1084 | } 1085 | // Timed-out? Log and break 1086 | $info = stream_get_meta_data($this->smtp_conn); 1087 | if ($info['timed_out']) { 1088 | $this->edebug( 1089 | 'SMTP -> get_lines(): timed-out (' . $this->Timeout . ' sec)', 1090 | self::DEBUG_LOWLEVEL 1091 | ); 1092 | break; 1093 | } 1094 | // Now check if reads took too long 1095 | if ($endtime and time() > $endtime) { 1096 | $this->edebug( 1097 | 'SMTP -> get_lines(): timelimit reached ('. 1098 | $this->Timelimit . ' sec)', 1099 | self::DEBUG_LOWLEVEL 1100 | ); 1101 | break; 1102 | } 1103 | } 1104 | return $data; 1105 | } 1106 | 1107 | /** 1108 | * Enable or disable VERP address generation. 1109 | * @param boolean $enabled 1110 | */ 1111 | public function setVerp($enabled = false) 1112 | { 1113 | $this->do_verp = $enabled; 1114 | } 1115 | 1116 | /** 1117 | * Get VERP address generation mode. 1118 | * @return boolean 1119 | */ 1120 | public function getVerp() 1121 | { 1122 | return $this->do_verp; 1123 | } 1124 | 1125 | /** 1126 | * Set error messages and codes. 1127 | * @param string $message The error message 1128 | * @param string $detail Further detail on the error 1129 | * @param string $smtp_code An associated SMTP error code 1130 | * @param string $smtp_code_ex Extended SMTP code 1131 | */ 1132 | protected function setError($message, $detail = '', $smtp_code = '', $smtp_code_ex = '') 1133 | { 1134 | $this->error = array( 1135 | 'error' => $message, 1136 | 'detail' => $detail, 1137 | 'smtp_code' => $smtp_code, 1138 | 'smtp_code_ex' => $smtp_code_ex 1139 | ); 1140 | } 1141 | 1142 | /** 1143 | * Set debug output method. 1144 | * @param string|callable $method The name of the mechanism to use for debugging output, or a callable to handle it. 1145 | */ 1146 | public function setDebugOutput($method = 'echo') 1147 | { 1148 | $this->Debugoutput = $method; 1149 | } 1150 | 1151 | /** 1152 | * Get debug output method. 1153 | * @return string 1154 | */ 1155 | public function getDebugOutput() 1156 | { 1157 | return $this->Debugoutput; 1158 | } 1159 | 1160 | /** 1161 | * Set debug output level. 1162 | * @param integer $level 1163 | */ 1164 | public function setDebugLevel($level = 0) 1165 | { 1166 | $this->do_debug = $level; 1167 | } 1168 | 1169 | /** 1170 | * Get debug output level. 1171 | * @return integer 1172 | */ 1173 | public function getDebugLevel() 1174 | { 1175 | return $this->do_debug; 1176 | } 1177 | 1178 | /** 1179 | * Set SMTP timeout. 1180 | * @param integer $timeout 1181 | */ 1182 | public function setTimeout($timeout = 0) 1183 | { 1184 | $this->Timeout = $timeout; 1185 | } 1186 | 1187 | /** 1188 | * Get SMTP timeout. 1189 | * @return integer 1190 | */ 1191 | public function getTimeout() 1192 | { 1193 | return $this->Timeout; 1194 | } 1195 | 1196 | /** 1197 | * Reports an error number and string. 1198 | * @param integer $errno The error number returned by PHP. 1199 | * @param string $errmsg The error message returned by PHP. 1200 | */ 1201 | protected function errorHandler($errno, $errmsg) 1202 | { 1203 | $notice = 'Connection: Failed to connect to server.'; 1204 | $this->setError( 1205 | $notice, 1206 | $errno, 1207 | $errmsg 1208 | ); 1209 | $this->edebug( 1210 | $notice . ' Error number ' . $errno . '. "Error notice: ' . $errmsg, 1211 | self::DEBUG_CONNECTION 1212 | ); 1213 | } 1214 | } 1215 | -------------------------------------------------------------------------------- /thanks.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Thanks 9 | 10 | 11 | Thanks, we have your message and will reply soon. 12 | 13 | --------------------------------------------------------------------------------