Overview

Namespaces

  • Composer
    • Autoload
  • Geekwright
    • RegDom
  • League
    • OAuth2
      • Client
        • Provider
  • None
  • Xmf
    • Database
    • Jwt
    • Key
    • Module
      • Helper

Classes

  • ArtObject
  • ArtObjectHandler
  • BloggerApi
  • CGIF
  • CGIFCOLORTABLE
  • CGIFFILEHEADER
  • CGIFIMAGE
  • CGIFIMAGEHEADER
  • CGIFLZW
  • Composer\Autoload\ClassLoader
  • Composer\Autoload\ComposerStaticInit274e5fff219a4f27a346e611b0580d6a
  • ComposerAutoloaderInit274e5fff219a4f27a346e611b0580d6a
  • Config_File
  • Cookie
  • Criteria
  • CriteriaCompo
  • CriteriaElement
  • Database
  • Db_manager
  • ErrorHandler
  • FormDhtmlTextArea
  • FormTextArea
  • Geekwright\RegDom\PublicSuffixList
  • Geekwright\RegDom\RegisteredDomain
  • HTMLPurifier
  • League\OAuth2\Client\Provider\Google
  • MetaWeblogApi
  • ModuleAdmin
  • MovableTypeApi
  • MyTextSanitizer
  • MyTextSanitizerExtended
  • MyTextSanitizerExtension
  • MytsCensor
  • MytsFlash
  • MytsIframe
  • MytsImage
  • MytsLi
  • MytsMms
  • MytsMp3
  • MytsRtsp
  • MytsSoundcloud
  • MytsSyntaxhighlight
  • MytsTextfilter
  • MytsUl
  • MytsWiki
  • MytsWmp
  • MytsYoutube
  • PathStuffController
  • PHPMailer
  • PHPMailerOAuth
  • PHPMailerOAuthGoogle
  • phpthumb
  • phpthumb_bmp
  • phpthumb_filters
  • phpthumb_functions
  • phpthumb_ico
  • phpUnsharpMask
  • PmCorePreload
  • PmMessage
  • PmMessageHandler
  • PmSystemPreload
  • POP3
  • ProfileCategory
  • ProfileCategoryHandler
  • ProfileCorePreload
  • ProfileField
  • ProfileFieldHandler
  • ProfileProfile
  • ProfileProfileHandler
  • ProfileRegstep
  • ProfileRegstepHandler
  • ProfileVisibility
  • ProfileVisibilityHandler
  • Protector
  • Protector_bruteforce_overrun_message
  • Protector_crawler_overrun_message
  • Protector_f5attack_overrun_message
  • Protector_postcommon_post_deny_by_httpbl
  • Protector_postcommon_post_deny_by_rbl
  • Protector_postcommon_post_htmlpurify4everyone
  • Protector_postcommon_post_htmlpurify4guest
  • Protector_postcommon_post_language_match
  • Protector_postcommon_post_need_multibyte
  • Protector_postcommon_post_register_moratorium
  • Protector_postcommon_post_stopforumspam
  • Protector_postcommon_register_insert_js_check
  • Protector_postcommon_register_stopforumspam
  • Protector_precommon_badip_errorlog
  • Protector_precommon_badip_message
  • Protector_precommon_badip_redirection
  • Protector_precommon_bwlimit_errorlog
  • Protector_precommon_bwlimit_message
  • Protector_prepurge_exit_message
  • Protector_spamcheck_overrun_message
  • ProtectorCorePreload
  • ProtectorFilterAbstract
  • ProtectorFilterHandler
  • ProtectorMySQLDatabase
  • ProtectorRegistry
  • ReCaptchaResponse
  • RpcArrayHandler
  • RpcBase64Handler
  • RpcBooleanHandler
  • RpcDateTimeHandler
  • RpcDoubleHandler
  • RpcIntHandler
  • RpcMemberHandler
  • RpcMethodNameHandler
  • RpcNameHandler
  • RpcStringHandler
  • RpcStructHandler
  • RpcValueHandler
  • RssAuthorHandler
  • RssCategoryHandler
  • RssChannelHandler
  • RssCommentsHandler
  • RssCopyrightHandler
  • RssDescriptionHandler
  • RssDocsHandler
  • RssGeneratorHandler
  • RssGuidHandler
  • RssHeightHandler
  • RssImageHandler
  • RssItemHandler
  • RssLanguageHandler
  • RssLastBuildDateHandler
  • RssLinkHandler
  • RssManagingEditorHandler
  • RssNameHandler
  • RssPubDateHandler
  • RssSourceHandler
  • RssTextInputHandler
  • RssTitleHandler
  • RssTtlHandler
  • RssUrlHandler
  • RssWebMasterHandler
  • RssWidthHandler
  • SaxParser
  • Smarty
  • Smarty_Compiler
  • SMTP
  • Snoopy
  • SqlUtility
  • SystemAvatar
  • SystemAvatarHandler
  • SystemBanner
  • SystemBannerclient
  • SystemBannerclientHandler
  • SystemBannerFinish
  • SystemBannerfinishHandler
  • SystemBannerHandler
  • SystemBlock
  • SystemBlockHandler
  • SystemBlockLinkModule
  • SystemBlockLinkModuleHandler
  • SystemBreadcrumb
  • SystemCorePreload
  • SystemFineAvatarUploadHandler
  • SystemFineImUploadHandler
  • SystemFineUploadHandler
  • SystemGroup
  • SystemGroupHandler
  • SystemMaintenance
  • SystemMenuHandler
  • SystemSmilies
  • SystemsmiliesHandler
  • SystemUserrank
  • SystemuserrankHandler
  • SystemUsers
  • SystemUsersHandler
  • Tar
  • ThemeSetAuthorHandler
  • ThemeSetDateCreatedHandler
  • ThemeSetDescriptionHandler
  • ThemeSetEmailHandler
  • ThemeSetFileTypeHandler
  • ThemeSetGeneratorHandler
  • ThemeSetImageHandler
  • ThemeSetLinkHandler
  • ThemeSetModuleHandler
  • ThemeSetNameHandler
  • ThemeSetTagHandler
  • ThemeSetTemplateHandler
  • TinyMCE
  • Xmf\Assert
  • Xmf\Database\Migrate
  • Xmf\Database\TableLoad
  • Xmf\Database\Tables
  • Xmf\Debug
  • Xmf\FilterInput
  • Xmf\Highlighter
  • Xmf\IPAddress
  • Xmf\Jwt\JsonWebToken
  • Xmf\Jwt\KeyFactory
  • Xmf\Jwt\TokenFactory
  • Xmf\Jwt\TokenReader
  • Xmf\Key\ArrayStorage
  • Xmf\Key\Basic
  • Xmf\Key\FileStorage
  • Xmf\Key\KeyAbstract
  • Xmf\Language
  • Xmf\Metagen
  • Xmf\Module\Admin
  • Xmf\Module\Helper
  • Xmf\Module\Helper\AbstractHelper
  • Xmf\Module\Helper\Cache
  • Xmf\Module\Helper\GenericHelper
  • Xmf\Module\Helper\Permission
  • Xmf\Module\Helper\Session
  • Xmf\Random
  • Xmf\Request
  • Xmf\StopWords
  • Xmf\Yaml
  • XmlTagHandler
  • XoopsApi
  • xoopsart
  • XoopsAuth
  • XoopsAuthAds
  • XoopsAuthFactory
  • XoopsAuthLdap
  • XoopsAuthProvisionning
  • XoopsAuthXoops
  • XoopsAvatar
  • XoopsAvatarHandler
  • XoopsBlock
  • XoopsBlockHandler
  • XoopsBlockInstance
  • XoopsBlockInstanceHandler
  • XoopsCache
  • XoopsCacheApc
  • XoopsCacheEngine
  • XoopsCacheFile
  • XoopsCacheMemcache
  • XoopsCacheModel
  • XoopsCacheModelHandler
  • XoopsCacheModelObject
  • XoopsCacheXcache
  • XoopsCaptcha
  • XoopsCaptchaImage
  • XoopsCaptchaImageHandler
  • XoopsCaptchaMethod
  • XoopsCaptchaRecaptcha
  • XoopsCaptchaRecaptcha2
  • XoopsCaptchaText
  • XoopsComment
  • XoopsCommentHandler
  • XoopsCommentRenderer
  • XoopsComments
  • XoopsConfigCategory
  • XoopsConfigCategoryHandler
  • XoopsConfigHandler
  • XoopsConfigItem
  • XoopsConfigItemHandler
  • XoopsConfigOption
  • XoopsConfigOptionHandler
  • XoopsDatabase
  • XoopsDatabaseFactory
  • XoopsDownloader
  • XoopsEditor
  • XoopsEditorHandler
  • XoopsErrorHandler
  • XoopsFile
  • XoopsFileHandler
  • XoopsFilterInput
  • XoopsFolderHandler
  • XoopsForm
  • XoopsFormButton
  • XoopsFormButtonTray
  • XoopsFormCaptcha
  • XoopsFormCheckBox
  • XoopsFormColorPicker
  • XoopsFormDateTime
  • XoopsFormDhtmlTextArea
  • XoopsFormEditor
  • XoopsFormElement
  • XoopsFormElementTray
  • XoopsFormFile
  • XoopsFormHidden
  • XoopsFormHiddenToken
  • XoopsFormLabel
  • XoopsFormPassword
  • XoopsFormRadio
  • XoopsFormRadioYN
  • XoopsFormRenderer
  • XoopsFormRendererBootstrap3
  • XoopsFormRendererLegacy
  • XoopsFormSelect
  • XoopsFormSelectCheckGroup
  • XoopsFormSelectCountry
  • XoopsFormSelectEditor
  • XoopsFormSelectGroup
  • XoopsFormSelectLang
  • XoopsFormSelectMatchOption
  • XoopsFormSelectTheme
  • XoopsFormSelectTimezone
  • XoopsFormSelectUser
  • XoopsFormText
  • XoopsFormTextArea
  • XoopsFormTextDateSelect
  • XoopsFormTinymce
  • XoopsGroup
  • XoopsGroupFormCheckBox
  • XoopsGroupHandler
  • XoopsGroupPerm
  • XoopsGroupPermForm
  • XoopsGroupPermHandler
  • XoopsGTicket
  • XoopsGuestUser
  • XoopsGuiDefault
  • XoopsGuiThadmin
  • XoopsGuiTransition
  • XoopsGuiZetadigme
  • XoopsHandlerRegistry
  • XoopsImage
  • XoopsImagecategory
  • XoopsImagecategoryHandler
  • XoopsImageHandler
  • XoopsImageSet
  • XoopsImagesetHandler
  • XoopsImagesetimg
  • XoopsImagesetimgHandler
  • XoopsInstallWizard
  • XoopsLists
  • XoopsLoad
  • XoopsLocal
  • XoopsLocalAbstract
  • XoopsLocalWrapper
  • XoopsLogger
  • XoopsMailer
  • XoopsMailerLocal
  • XoopsMediaUploader
  • XoopsMemberHandler
  • XoopsMembership
  • XoopsMembershipHandler
  • XoopsModelAbstract
  • XoopsModelFactory
  • XoopsModelJoint
  • XoopsModelRead
  • XoopsModelStats
  • XoopsModelSync
  • XoopsModelWrite
  • XoopsModule
  • XoopsModuleHandler
  • XoopsMultiMailer
  • XoopsMySQLDatabase
  • XoopsMySQLDatabaseProxy
  • XoopsMySQLDatabaseSafe
  • XoopsNotification
  • XoopsNotificationHandler
  • XoopsObject
  • XoopsObjectHandler
  • XoopsObjectTree
  • XoopsOnlineHandler
  • XoopsPageNav
  • XoopsPersistableObjectHandler
  • XoopsPreload
  • XoopsPreloadItem
  • XoopsPrivmessage
  • XoopsPrivmessageHandler
  • XoopsRank
  • XoopsRankHandler
  • XoopsRequest
  • XoopsSecurity
  • XoopsSessionHandler
  • XoopsSimpleForm
  • XoopsStory
  • XoopsSystemCpanel
  • XoopsSystemGui
  • XoopsTableForm
  • XoopsTarDownloader
  • XoopsThemeForm
  • XoopsThemeSetParser
  • XoopsTopic
  • XoopsTpl
  • XoopsTplfile
  • XoopsTplfileHandler
  • XoopsTplset
  • XoopsTplsetHandler
  • XoopsTree
  • XoopsUser
  • XoopsUserHandler
  • XoopsUserUtility
  • XoopsUtility
  • XoopsXmlRpcApi
  • XoopsXmlRpcArray
  • XoopsXmlRpcBase64
  • XoopsXmlRpcBoolean
  • XoopsXmlRpcDatetime
  • XoopsXmlRpcDocument
  • XoopsXmlRpcDouble
  • XoopsXmlRpcFault
  • XoopsXmlRpcInt
  • XoopsXmlRpcParser
  • XoopsXmlRpcRequest
  • XoopsXmlRpcResponse
  • XoopsXmlRpcString
  • XoopsXmlRpcStruct
  • XoopsXmlRpcTag
  • XoopsXmlRss2Parser
  • XoopsZipDownloader
  • xos_kernel_Xoops2
  • xos_logos_PageBuilder
  • xos_opal_AdminThemeFactory
  • xos_opal_Theme
  • xos_opal_ThemeFactory
  • XoUser
  • XoUserHandler
  • Zipfile

Interfaces

  • Xmf\Key\StorageInterface
  • XoopsFormRendererInterface

Exceptions

  • phpmailerException

Functions

  • __autoload
  • _recaptcha_aes_encrypt
  • _recaptcha_aes_pad
  • _recaptcha_http_post
  • _recaptcha_mailhide_email_parts
  • _recaptcha_mailhide_urlbase64
  • _recaptcha_qsencode
  • _smarty_regex_replace_check
  • _smarty_sort_length
  • admin_refcheck
  • b_system_comments_edit
  • b_system_comments_show
  • b_system_info_edit
  • b_system_info_show
  • b_system_login_show
  • b_system_main_show
  • b_system_newmembers_edit
  • b_system_newmembers_show
  • b_system_notification_show
  • b_system_online_show
  • b_system_search_show
  • b_system_themes_edit
  • b_system_themes_show
  • b_system_topposters_edit
  • b_system_topposters_show
  • b_system_user_show
  • b_system_waiting_show
  • bannerstats
  • change_banner_url_by_client
  • checkEmail
  • clickbanner
  • clientlogin
  • closeTable
  • closeThread
  • CloseWaitBox
  • Composer\Autoload\includeFile
  • composerRequire274e5fff219a4f27a346e611b0580d6a
  • createConfigform
  • createThemeform
  • doConditionalGet
  • emailStats
  • exit404BadReq
  • fatalPhpErrorHandler
  • file_get_contents
  • file_put_contents
  • findSharp
  • form_user
  • formatTimestamp
  • formatURL
  • gd_info
  • genPathCheckHtml
  • get_request_method
  • get_writeoks_from_protector
  • getcss
  • getDbCharsets
  • getDbCollations
  • getDirList
  • getMailer
  • getTheme
  • gif_getSize
  • gif_loadFile
  • gif_loadFileToGDimageResource
  • gif_outputAsBmp
  • gif_outputAsJpeg
  • gif_outputAsPng
  • HTMLPurifier
  • imagealphablending
  • imageBrowser
  • imageCreateCorners
  • imageFilenameCheck
  • imagesavealpha
  • install_acceptUser
  • install_finalize
  • is_executable
  • kses
  • langDropdown
  • load_functions
  • load_object
  • load_objectHandler
  • loadModuleAdminMenu
  • make_cblock
  • make_data
  • make_groups
  • make_sidebar
  • mod_clearCacheFile
  • mod_clearConfg
  • mod_clearConfig
  • mod_clearFile
  • mod_clearSmartyCache
  • mod_constant
  • mod_createCacheFile
  • mod_createCacheFile_byGroup
  • mod_createFile
  • mod_DB_prefix
  • mod_fetchConfg
  • mod_fetchConfig
  • mod_generateCacheId
  • mod_generateCacheId_byGroup
  • mod_getDirname
  • mod_getIP
  • mod_getMysqlVersion
  • mod_getUnameFromId
  • mod_getUnameFromIds
  • mod_isModuleAction
  • mod_loadCacheFile
  • mod_loadCacheFile_byGroup
  • mod_loadConfg
  • mod_loadConfig
  • mod_loadFile
  • mod_loadFunctions
  • mod_loadRenderer
  • mod_message
  • modify_chmod
  • myTextForm
  • notificationCategoryInfo
  • notificationCommentCategoryInfo
  • notificationEnabled
  • notificationEventEnabled
  • notificationEventInfo
  • notificationEvents
  • notificationGenerateConfig
  • notificationSubscribableCategoryInfo
  • openTable
  • openThread
  • OpenWaitBox
  • PHPMailerAutoload
  • phpThumbURL
  • preg_quote
  • profile_getFieldForm
  • profile_getRegisterForm
  • profile_getStepForm
  • profile_getUserForm
  • profile_install_addCategory
  • profile_install_addField
  • profile_install_addStep
  • profile_install_initializeProfiles
  • profile_install_setPermissions
  • protector_message_append_oninstall
  • protector_message_append_onuninstall
  • protector_message_append_onupdate
  • protector_notify_base
  • protector_oninstall_base
  • protector_onuninstall_base
  • protector_onupdate_base
  • protector_postcommon
  • protector_prepare
  • recaptcha_check_answer
  • recaptcha_get_html
  • recaptcha_get_signup_url
  • recaptcha_mailhide_html
  • recaptcha_mailhide_url
  • redirect_header
  • RedirectToCachedFile
  • SendSaveAsFileHeaderIfNeeded
  • showbanner
  • showThread
  • smarty_block_textformat
  • smarty_compiler_assign
  • smarty_compiler_foreachq
  • smarty_compiler_includeq
  • smarty_compiler_xoAdminIcons
  • smarty_compiler_xoAdminNav
  • smarty_compiler_xoAppUrl
  • smarty_compiler_xoImgUrl
  • smarty_compiler_xoModuleIcons16
  • smarty_compiler_xoModuleIcons32
  • smarty_compiler_xoModuleIconsBookmarks
  • smarty_core_assemble_plugin_filepath
  • smarty_core_assign_smarty_interface
  • smarty_core_create_dir_structure
  • smarty_core_display_debug_console
  • smarty_core_get_include_path
  • smarty_core_get_microtime
  • smarty_core_get_php_resource
  • smarty_core_is_secure
  • smarty_core_is_trusted
  • smarty_core_load_plugins
  • smarty_core_load_resource_plugin
  • smarty_core_process_cached_inserts
  • smarty_core_process_compiled_include
  • smarty_core_read_cache_file
  • smarty_core_rm_auto
  • smarty_core_rmdir
  • smarty_core_run_insert_handler
  • smarty_core_smarty_include_php
  • smarty_core_write_cache_file
  • smarty_core_write_compiled_include
  • smarty_core_write_compiled_resource
  • smarty_core_write_file
  • smarty_function_assign_debug_info
  • smarty_function_block
  • smarty_function_config_load
  • smarty_function_counter
  • smarty_function_cycle
  • smarty_function_debug
  • smarty_function_escape_special_chars
  • smarty_function_eval
  • smarty_function_fetch
  • smarty_function_html_checkboxes
  • smarty_function_html_checkboxes_output
  • smarty_function_html_image
  • smarty_function_html_options
  • smarty_function_html_options_optgroup
  • smarty_function_html_options_optoutput
  • smarty_function_html_radios
  • smarty_function_html_radios_output
  • smarty_function_html_select_date
  • smarty_function_html_select_time
  • smarty_function_html_table
  • smarty_function_html_table_cycle
  • smarty_function_mailto
  • smarty_function_math
  • smarty_function_popup
  • smarty_function_popup_init
  • smarty_function_securityToken
  • smarty_function_xoInboxCount
  • smarty_function_xoMemberInfo
  • smarty_function_xoops_link
  • smarty_function_xoPageNav
  • smarty_make_timestamp
  • smarty_modifier_capitalize
  • smarty_modifier_capitalize_ucfirst
  • smarty_modifier_cat
  • smarty_modifier_count_characters
  • smarty_modifier_count_paragraphs
  • smarty_modifier_count_sentences
  • smarty_modifier_count_words
  • smarty_modifier_date_format
  • smarty_modifier_debug_print_var
  • smarty_modifier_default
  • smarty_modifier_escape
  • smarty_modifier_indent
  • smarty_modifier_lower
  • smarty_modifier_nl2br
  • smarty_modifier_regex_replace
  • smarty_modifier_replace
  • smarty_modifier_spacify
  • smarty_modifier_string_format
  • smarty_modifier_strip
  • smarty_modifier_strip_tags
  • smarty_modifier_truncate
  • smarty_modifier_upper
  • smarty_modifier_wordwrap
  • smarty_outputfilter_trimwhitespace
  • smarty_outputfilter_trimwhitespace_replace
  • smarty_resource_db_secure
  • smarty_resource_db_source
  • smarty_resource_db_timestamp
  • smarty_resource_db_tplinfo
  • smarty_resource_db_trusted
  • synchronize
  • system_AdminIcons
  • system_adminVersion
  • system_CleanVars
  • system_loadLanguage
  • system_loadTemplate
  • themecenterposts
  • update_system_v211
  • userCheck
  • userTimeToServerTime
  • validateDbCharset
  • writeLicenseKey
  • xoBuildLicenceKey
  • xoDiag
  • xoDiagBoolSetting
  • xoDiagIfWritable
  • xoFormBlockCollation
  • xoFormField
  • xoFormFieldCharset
  • xoFormFieldCollation
  • xoFormSelect
  • xoops_aw_decode
  • xoops_aw_encode
  • xoops_bin2hex
  • xoops_comment_count
  • xoops_comment_delete
  • xoops_confirm
  • xoops_convert_decode
  • xoops_convert_encode
  • xoops_convert_encoding
  • xoops_cp_footer
  • xoops_cp_header
  • xoops_error
  • xoops_footer
  • xoops_getActiveModules
  • xoops_getbanner
  • xoops_getBaseDomain
  • xoops_getConfigOption
  • xoops_getcss
  • xoops_getenv
  • xoops_getHandler
  • xoops_getLinkedUnameFromId
  • xoops_getMailer
  • xoops_getModuleHandler
  • xoops_getModuleOption
  • xoops_getOption
  • xoops_getrank
  • xoops_getUrlDomain
  • xoops_getUserTimestamp
  • xoops_groupperm_deletebymoditem
  • xoops_header
  • xoops_hex2bin
  • xoops_isActiveModule
  • xoops_ishexstr
  • xoops_load
  • xoops_load_lang_file
  • xoops_loadLanguage
  • xoops_local
  • xoops_makepass
  • xoops_message
  • xoops_module_activate
  • xoops_module_change
  • xoops_module_deactivate
  • xoops_module_delayed_clean_cache
  • xoops_module_get_admin_menu
  • xoops_module_gettemplate
  • xoops_module_install
  • xoops_module_install_pm
  • xoops_module_install_profile
  • xoops_module_log_header
  • xoops_module_uninstall
  • xoops_module_update
  • xoops_module_update_pm
  • xoops_module_update_profile
  • xoops_module_update_system
  • xoops_module_write_admin_menu
  • xoops_notification_deletebyitem
  • xoops_notification_deletebymodule
  • xoops_notification_deletebyuser
  • xoops_refcheck
  • xoops_result
  • xoops_setActiveModules
  • xoops_setConfigOption
  • xoops_substr
  • xoops_template_clear_module_cache
  • xoops_template_touch
  • xoops_trim
  • xoops_utf8_encode
  • xoops_write_index_file
  • xoopsCodeTarea
  • xoopseditor_get_rootpath
  • XoopsErrorHandler_HandleError
  • xoopsfwrite
  • xoopsSmilies
  • xoPassField
  • xoPhpVersion
  • xoPutLicenseKey
  • xoStripeKey
  • Overview
  • Namespace
  • Class
  • Tree
   1: <?php
   2: /**
   3:  * PHPMailer - PHP email creation and transport class.
   4:  * PHP Version 5
   5:  * @package PHPMailer
   6:  * @link https://github.com/PHPMailer/PHPMailer/ The PHPMailer GitHub project
   7:  * @author Marcus Bointon (Synchro/coolbru) <phpmailer@synchromedia.co.uk>
   8:  * @author Jim Jagielski (jimjag) <jimjag@gmail.com>
   9:  * @author Andy Prevost (codeworxtech) <codeworxtech@users.sourceforge.net>
  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 - PHP email creation and transport class.
  22:  * @package PHPMailer
  23:  * @author Marcus Bointon (Synchro/coolbru) <phpmailer@synchromedia.co.uk>
  24:  * @author Jim Jagielski (jimjag) <jimjag@gmail.com>
  25:  * @author Andy Prevost (codeworxtech) <codeworxtech@users.sourceforge.net>
  26:  * @author Brent R. Matzelle (original founder)
  27:  */
  28: class PHPMailer
  29: {
  30:     /**
  31:      * The PHPMailer Version number.
  32:      * @var string
  33:      */
  34:     public $Version = '5.2.21';
  35: 
  36:     /**
  37:      * Email priority.
  38:      * Options: null (default), 1 = High, 3 = Normal, 5 = low.
  39:      * When null, the header is not set at all.
  40:      * @var integer
  41:      */
  42:     public $Priority = null;
  43: 
  44:     /**
  45:      * The character set of the message.
  46:      * @var string
  47:      */
  48:     public $CharSet = 'iso-8859-1';
  49: 
  50:     /**
  51:      * The MIME Content-type of the message.
  52:      * @var string
  53:      */
  54:     public $ContentType = 'text/plain';
  55: 
  56:     /**
  57:      * The message encoding.
  58:      * Options: "8bit", "7bit", "binary", "base64", and "quoted-printable".
  59:      * @var string
  60:      */
  61:     public $Encoding = '8bit';
  62: 
  63:     /**
  64:      * Holds the most recent mailer error message.
  65:      * @var string
  66:      */
  67:     public $ErrorInfo = '';
  68: 
  69:     /**
  70:      * The From email address for the message.
  71:      * @var string
  72:      */
  73:     public $From = 'root@localhost';
  74: 
  75:     /**
  76:      * The From name of the message.
  77:      * @var string
  78:      */
  79:     public $FromName = 'Root User';
  80: 
  81:     /**
  82:      * The Sender email (Return-Path) of the message.
  83:      * If not empty, will be sent via -f to sendmail or as 'MAIL FROM' in smtp mode.
  84:      * @var string
  85:      */
  86:     public $Sender = '';
  87: 
  88:     /**
  89:      * The Return-Path of the message.
  90:      * If empty, it will be set to either From or Sender.
  91:      * @var string
  92:      * @deprecated Email senders should never set a return-path header;
  93:      * it's the receiver's job (RFC5321 section 4.4), so this no longer does anything.
  94:      * @link https://tools.ietf.org/html/rfc5321#section-4.4 RFC5321 reference
  95:      */
  96:     public $ReturnPath = '';
  97: 
  98:     /**
  99:      * The Subject of the message.
 100:      * @var string
 101:      */
 102:     public $Subject = '';
 103: 
 104:     /**
 105:      * An HTML or plain text message body.
 106:      * If HTML then call isHTML(true).
 107:      * @var string
 108:      */
 109:     public $Body = '';
 110: 
 111:     /**
 112:      * The plain-text message body.
 113:      * This body can be read by mail clients that do not have HTML email
 114:      * capability such as mutt & Eudora.
 115:      * Clients that can read HTML will view the normal Body.
 116:      * @var string
 117:      */
 118:     public $AltBody = '';
 119: 
 120:     /**
 121:      * An iCal message part body.
 122:      * Only supported in simple alt or alt_inline message types
 123:      * To generate iCal events, use the bundled extras/EasyPeasyICS.php class or iCalcreator
 124:      * @link http://sprain.ch/blog/downloads/php-class-easypeasyics-create-ical-files-with-php/
 125:      * @link http://kigkonsult.se/iCalcreator/
 126:      * @var string
 127:      */
 128:     public $Ical = '';
 129: 
 130:     /**
 131:      * The complete compiled MIME message body.
 132:      * @access protected
 133:      * @var string
 134:      */
 135:     protected $MIMEBody = '';
 136: 
 137:     /**
 138:      * The complete compiled MIME message headers.
 139:      * @var string
 140:      * @access protected
 141:      */
 142:     protected $MIMEHeader = '';
 143: 
 144:     /**
 145:      * Extra headers that createHeader() doesn't fold in.
 146:      * @var string
 147:      * @access protected
 148:      */
 149:     protected $mailHeader = '';
 150: 
 151:     /**
 152:      * Word-wrap the message body to this number of chars.
 153:      * Set to 0 to not wrap. A useful value here is 78, for RFC2822 section 2.1.1 compliance.
 154:      * @var integer
 155:      */
 156:     public $WordWrap = 0;
 157: 
 158:     /**
 159:      * Which method to use to send mail.
 160:      * Options: "mail", "sendmail", or "smtp".
 161:      * @var string
 162:      */
 163:     public $Mailer = 'mail';
 164: 
 165:     /**
 166:      * The path to the sendmail program.
 167:      * @var string
 168:      */
 169:     public $Sendmail = '/usr/sbin/sendmail';
 170: 
 171:     /**
 172:      * Whether mail() uses a fully sendmail-compatible MTA.
 173:      * One which supports sendmail's "-oi -f" options.
 174:      * @var boolean
 175:      */
 176:     public $UseSendmailOptions = true;
 177: 
 178:     /**
 179:      * Path to PHPMailer plugins.
 180:      * Useful if the SMTP class is not in the PHP include path.
 181:      * @var string
 182:      * @deprecated Should not be needed now there is an autoloader.
 183:      */
 184:     public $PluginDir = '';
 185: 
 186:     /**
 187:      * The email address that a reading confirmation should be sent to, also known as read receipt.
 188:      * @var string
 189:      */
 190:     public $ConfirmReadingTo = '';
 191: 
 192:     /**
 193:      * The hostname to use in the Message-ID header and as default HELO string.
 194:      * If empty, PHPMailer attempts to find one with, in order,
 195:      * $_SERVER['SERVER_NAME'], gethostname(), php_uname('n'), or the value
 196:      * 'localhost.localdomain'.
 197:      * @var string
 198:      */
 199:     public $Hostname = '';
 200: 
 201:     /**
 202:      * An ID to be used in the Message-ID header.
 203:      * If empty, a unique id will be generated.
 204:      * You can set your own, but it must be in the format "<id@domain>",
 205:      * as defined in RFC5322 section 3.6.4 or it will be ignored.
 206:      * @see https://tools.ietf.org/html/rfc5322#section-3.6.4
 207:      * @var string
 208:      */
 209:     public $MessageID = '';
 210: 
 211:     /**
 212:      * The message Date to be used in the Date header.
 213:      * If empty, the current date will be added.
 214:      * @var string
 215:      */
 216:     public $MessageDate = '';
 217: 
 218:     /**
 219:      * SMTP hosts.
 220:      * Either a single hostname or multiple semicolon-delimited hostnames.
 221:      * You can also specify a different port
 222:      * for each host by using this format: [hostname:port]
 223:      * (e.g. "smtp1.example.com:25;smtp2.example.com").
 224:      * You can also specify encryption type, for example:
 225:      * (e.g. "tls://smtp1.example.com:587;ssl://smtp2.example.com:465").
 226:      * Hosts will be tried in order.
 227:      * @var string
 228:      */
 229:     public $Host = 'localhost';
 230: 
 231:     /**
 232:      * The default SMTP server port.
 233:      * @var integer
 234:      * @TODO Why is this needed when the SMTP class takes care of it?
 235:      */
 236:     public $Port = 25;
 237: 
 238:     /**
 239:      * The SMTP HELO of the message.
 240:      * Default is $Hostname. If $Hostname is empty, PHPMailer attempts to find
 241:      * one with the same method described above for $Hostname.
 242:      * @var string
 243:      * @see PHPMailer::$Hostname
 244:      */
 245:     public $Helo = '';
 246: 
 247:     /**
 248:      * What kind of encryption to use on the SMTP connection.
 249:      * Options: '', 'ssl' or 'tls'
 250:      * @var string
 251:      */
 252:     public $SMTPSecure = '';
 253: 
 254:     /**
 255:      * Whether to enable TLS encryption automatically if a server supports it,
 256:      * even if `SMTPSecure` is not set to 'tls'.
 257:      * Be aware that in PHP >= 5.6 this requires that the server's certificates are valid.
 258:      * @var boolean
 259:      */
 260:     public $SMTPAutoTLS = true;
 261: 
 262:     /**
 263:      * Whether to use SMTP authentication.
 264:      * Uses the Username and Password properties.
 265:      * @var boolean
 266:      * @see PHPMailer::$Username
 267:      * @see PHPMailer::$Password
 268:      */
 269:     public $SMTPAuth = false;
 270: 
 271:     /**
 272:      * Options array passed to stream_context_create when connecting via SMTP.
 273:      * @var array
 274:      */
 275:     public $SMTPOptions = array();
 276: 
 277:     /**
 278:      * SMTP username.
 279:      * @var string
 280:      */
 281:     public $Username = '';
 282: 
 283:     /**
 284:      * SMTP password.
 285:      * @var string
 286:      */
 287:     public $Password = '';
 288: 
 289:     /**
 290:      * SMTP auth type.
 291:      * Options are CRAM-MD5, LOGIN, PLAIN, NTLM, XOAUTH2, attempted in that order if not specified
 292:      * @var string
 293:      */
 294:     public $AuthType = '';
 295: 
 296:     /**
 297:      * SMTP realm.
 298:      * Used for NTLM auth
 299:      * @var string
 300:      */
 301:     public $Realm = '';
 302: 
 303:     /**
 304:      * SMTP workstation.
 305:      * Used for NTLM auth
 306:      * @var string
 307:      */
 308:     public $Workstation = '';
 309: 
 310:     /**
 311:      * The SMTP server timeout in seconds.
 312:      * Default of 5 minutes (300sec) is from RFC2821 section 4.5.3.2
 313:      * @var integer
 314:      */
 315:     public $Timeout = 300;
 316: 
 317:     /**
 318:      * SMTP class debug output mode.
 319:      * Debug output level.
 320:      * Options:
 321:      * * `0` No output
 322:      * * `1` Commands
 323:      * * `2` Data and commands
 324:      * * `3` As 2 plus connection status
 325:      * * `4` Low-level data output
 326:      * @var integer
 327:      * @see SMTP::$do_debug
 328:      */
 329:     public $SMTPDebug = 0;
 330: 
 331:     /**
 332:      * How to handle debug output.
 333:      * Options:
 334:      * * `echo` Output plain-text as-is, appropriate for CLI
 335:      * * `html` Output escaped, line breaks converted to `<br>`, appropriate for browser output
 336:      * * `error_log` Output to error log as configured in php.ini
 337:      *
 338:      * Alternatively, you can provide a callable expecting two params: a message string and the debug level:
 339:      * <code>
 340:      * $mail->Debugoutput = function($str, $level) {echo "debug level $level; message: $str";};
 341:      * </code>
 342:      * @var string|callable
 343:      * @see SMTP::$Debugoutput
 344:      */
 345:     public $Debugoutput = 'echo';
 346: 
 347:     /**
 348:      * Whether to keep SMTP connection open after each message.
 349:      * If this is set to true then to close the connection
 350:      * requires an explicit call to smtpClose().
 351:      * @var boolean
 352:      */
 353:     public $SMTPKeepAlive = false;
 354: 
 355:     /**
 356:      * Whether to split multiple to addresses into multiple messages
 357:      * or send them all in one message.
 358:      * Only supported in `mail` and `sendmail` transports, not in SMTP.
 359:      * @var boolean
 360:      */
 361:     public $SingleTo = false;
 362: 
 363:     /**
 364:      * Storage for addresses when SingleTo is enabled.
 365:      * @var array
 366:      * @TODO This should really not be public
 367:      */
 368:     public $SingleToArray = array();
 369: 
 370:     /**
 371:      * Whether to generate VERP addresses on send.
 372:      * Only applicable when sending via SMTP.
 373:      * @link https://en.wikipedia.org/wiki/Variable_envelope_return_path
 374:      * @link http://www.postfix.org/VERP_README.html Postfix VERP info
 375:      * @var boolean
 376:      */
 377:     public $do_verp = false;
 378: 
 379:     /**
 380:      * Whether to allow sending messages with an empty body.
 381:      * @var boolean
 382:      */
 383:     public $AllowEmpty = false;
 384: 
 385:     /**
 386:      * The default line ending.
 387:      * @note The default remains "\n". We force CRLF where we know
 388:      *        it must be used via self::CRLF.
 389:      * @var string
 390:      */
 391:     public $LE = "\n";
 392: 
 393:     /**
 394:      * DKIM selector.
 395:      * @var string
 396:      */
 397:     public $DKIM_selector = '';
 398: 
 399:     /**
 400:      * DKIM Identity.
 401:      * Usually the email address used as the source of the email.
 402:      * @var string
 403:      */
 404:     public $DKIM_identity = '';
 405: 
 406:     /**
 407:      * DKIM passphrase.
 408:      * Used if your key is encrypted.
 409:      * @var string
 410:      */
 411:     public $DKIM_passphrase = '';
 412: 
 413:     /**
 414:      * DKIM signing domain name.
 415:      * @example 'example.com'
 416:      * @var string
 417:      */
 418:     public $DKIM_domain = '';
 419: 
 420:     /**
 421:      * DKIM private key file path.
 422:      * @var string
 423:      */
 424:     public $DKIM_private = '';
 425: 
 426:     /**
 427:      * DKIM private key string.
 428:      * If set, takes precedence over `$DKIM_private`.
 429:      * @var string
 430:      */
 431:     public $DKIM_private_string = '';
 432: 
 433:     /**
 434:      * Callback Action function name.
 435:      *
 436:      * The function that handles the result of the send email action.
 437:      * It is called out by send() for each email sent.
 438:      *
 439:      * Value can be any php callable: http://www.php.net/is_callable
 440:      *
 441:      * Parameters:
 442:      *   boolean $result        result of the send action
 443:      *   string  $to            email address of the recipient
 444:      *   string  $cc            cc email addresses
 445:      *   string  $bcc           bcc email addresses
 446:      *   string  $subject       the subject
 447:      *   string  $body          the email body
 448:      *   string  $from          email address of sender
 449:      * @var string
 450:      */
 451:     public $action_function = '';
 452: 
 453:     /**
 454:      * What to put in the X-Mailer header.
 455:      * Options: An empty string for PHPMailer default, whitespace for none, or a string to use
 456:      * @var string
 457:      */
 458:     public $XMailer = '';
 459: 
 460:     /**
 461:      * Which validator to use by default when validating email addresses.
 462:      * May be a callable to inject your own validator, but there are several built-in validators.
 463:      * @see PHPMailer::validateAddress()
 464:      * @var string|callable
 465:      * @static
 466:      */
 467:     public static $validator = 'auto';
 468: 
 469:     /**
 470:      * An instance of the SMTP sender class.
 471:      * @var SMTP
 472:      * @access protected
 473:      */
 474:     protected $smtp = null;
 475: 
 476:     /**
 477:      * The array of 'to' names and addresses.
 478:      * @var array
 479:      * @access protected
 480:      */
 481:     protected $to = array();
 482: 
 483:     /**
 484:      * The array of 'cc' names and addresses.
 485:      * @var array
 486:      * @access protected
 487:      */
 488:     protected $cc = array();
 489: 
 490:     /**
 491:      * The array of 'bcc' names and addresses.
 492:      * @var array
 493:      * @access protected
 494:      */
 495:     protected $bcc = array();
 496: 
 497:     /**
 498:      * The array of reply-to names and addresses.
 499:      * @var array
 500:      * @access protected
 501:      */
 502:     protected $ReplyTo = array();
 503: 
 504:     /**
 505:      * An array of all kinds of addresses.
 506:      * Includes all of $to, $cc, $bcc
 507:      * @var array
 508:      * @access protected
 509:      * @see PHPMailer::$to @see PHPMailer::$cc @see PHPMailer::$bcc
 510:      */
 511:     protected $all_recipients = array();
 512: 
 513:     /**
 514:      * An array of names and addresses queued for validation.
 515:      * In send(), valid and non duplicate entries are moved to $all_recipients
 516:      * and one of $to, $cc, or $bcc.
 517:      * This array is used only for addresses with IDN.
 518:      * @var array
 519:      * @access protected
 520:      * @see PHPMailer::$to @see PHPMailer::$cc @see PHPMailer::$bcc
 521:      * @see PHPMailer::$all_recipients
 522:      */
 523:     protected $RecipientsQueue = array();
 524: 
 525:     /**
 526:      * An array of reply-to names and addresses queued for validation.
 527:      * In send(), valid and non duplicate entries are moved to $ReplyTo.
 528:      * This array is used only for addresses with IDN.
 529:      * @var array
 530:      * @access protected
 531:      * @see PHPMailer::$ReplyTo
 532:      */
 533:     protected $ReplyToQueue = array();
 534: 
 535:     /**
 536:      * The array of attachments.
 537:      * @var array
 538:      * @access protected
 539:      */
 540:     protected $attachment = array();
 541: 
 542:     /**
 543:      * The array of custom headers.
 544:      * @var array
 545:      * @access protected
 546:      */
 547:     protected $CustomHeader = array();
 548: 
 549:     /**
 550:      * The most recent Message-ID (including angular brackets).
 551:      * @var string
 552:      * @access protected
 553:      */
 554:     protected $lastMessageID = '';
 555: 
 556:     /**
 557:      * The message's MIME type.
 558:      * @var string
 559:      * @access protected
 560:      */
 561:     protected $message_type = '';
 562: 
 563:     /**
 564:      * The array of MIME boundary strings.
 565:      * @var array
 566:      * @access protected
 567:      */
 568:     protected $boundary = array();
 569: 
 570:     /**
 571:      * The array of available languages.
 572:      * @var array
 573:      * @access protected
 574:      */
 575:     protected $language = array();
 576: 
 577:     /**
 578:      * The number of errors encountered.
 579:      * @var integer
 580:      * @access protected
 581:      */
 582:     protected $error_count = 0;
 583: 
 584:     /**
 585:      * The S/MIME certificate file path.
 586:      * @var string
 587:      * @access protected
 588:      */
 589:     protected $sign_cert_file = '';
 590: 
 591:     /**
 592:      * The S/MIME key file path.
 593:      * @var string
 594:      * @access protected
 595:      */
 596:     protected $sign_key_file = '';
 597: 
 598:     /**
 599:      * The optional S/MIME extra certificates ("CA Chain") file path.
 600:      * @var string
 601:      * @access protected
 602:      */
 603:     protected $sign_extracerts_file = '';
 604: 
 605:     /**
 606:      * The S/MIME password for the key.
 607:      * Used only if the key is encrypted.
 608:      * @var string
 609:      * @access protected
 610:      */
 611:     protected $sign_key_pass = '';
 612: 
 613:     /**
 614:      * Whether to throw exceptions for errors.
 615:      * @var boolean
 616:      * @access protected
 617:      */
 618:     protected $exceptions = false;
 619: 
 620:     /**
 621:      * Unique ID used for message ID and boundaries.
 622:      * @var string
 623:      * @access protected
 624:      */
 625:     protected $uniqueid = '';
 626: 
 627:     /**
 628:      * Error severity: message only, continue processing.
 629:      */
 630:     const STOP_MESSAGE = 0;
 631: 
 632:     /**
 633:      * Error severity: message, likely ok to continue processing.
 634:      */
 635:     const STOP_CONTINUE = 1;
 636: 
 637:     /**
 638:      * Error severity: message, plus full stop, critical error reached.
 639:      */
 640:     const STOP_CRITICAL = 2;
 641: 
 642:     /**
 643:      * SMTP RFC standard line ending.
 644:      */
 645:     const CRLF = "\r\n";
 646: 
 647:     /**
 648:      * The maximum line length allowed by RFC 2822 section 2.1.1
 649:      * @var integer
 650:      */
 651:     const MAX_LINE_LENGTH = 998;
 652: 
 653:     /**
 654:      * Constructor.
 655:      * @param boolean $exceptions Should we throw external exceptions?
 656:      */
 657:     public function __construct($exceptions = null)
 658:     {
 659:         if ($exceptions !== null) {
 660:             $this->exceptions = (boolean)$exceptions;
 661:         }
 662:     }
 663: 
 664:     /**
 665:      * Destructor.
 666:      */
 667:     public function __destruct()
 668:     {
 669:         //Close any open SMTP connection nicely
 670:         $this->smtpClose();
 671:     }
 672: 
 673:     /**
 674:      * Call mail() in a safe_mode-aware fashion.
 675:      * Also, unless sendmail_path points to sendmail (or something that
 676:      * claims to be sendmail), don't pass params (not a perfect fix,
 677:      * but it will do)
 678:      * @param string $to To
 679:      * @param string $subject Subject
 680:      * @param string $body Message Body
 681:      * @param string $header Additional Header(s)
 682:      * @param string $params Params
 683:      * @access private
 684:      * @return boolean
 685:      */
 686:     private function mailPassthru($to, $subject, $body, $header, $params)
 687:     {
 688:         //Check overloading of mail function to avoid double-encoding
 689:         if (ini_get('mbstring.func_overload') & 1) {
 690:             $subject = $this->secureHeader($subject);
 691:         } else {
 692:             $subject = $this->encodeHeader($this->secureHeader($subject));
 693:         }
 694: 
 695:         //Can't use additional_parameters in safe_mode, calling mail() with null params breaks
 696:         //@link http://php.net/manual/en/function.mail.php
 697:         if (ini_get('safe_mode') or !$this->UseSendmailOptions or is_null($params)) {
 698:             $result = @mail($to, $subject, $body, $header);
 699:         } else {
 700:             $result = @mail($to, $subject, $body, $header, $params);
 701:         }
 702:         return $result;
 703:     }
 704:     /**
 705:      * Output debugging info via user-defined method.
 706:      * Only generates output if SMTP debug output is enabled (@see SMTP::$do_debug).
 707:      * @see PHPMailer::$Debugoutput
 708:      * @see PHPMailer::$SMTPDebug
 709:      * @param string $str
 710:      */
 711:     protected function edebug($str)
 712:     {
 713:         if ($this->SMTPDebug <= 0) {
 714:             return;
 715:         }
 716:         //Avoid clash with built-in function names
 717:         if (!in_array($this->Debugoutput, array('error_log', 'html', 'echo')) and is_callable($this->Debugoutput)) {
 718:             call_user_func($this->Debugoutput, $str, $this->SMTPDebug);
 719:             return;
 720:         }
 721:         switch ($this->Debugoutput) {
 722:             case 'error_log':
 723:                 //Don't output, just log
 724:                 error_log($str);
 725:                 break;
 726:             case 'html':
 727:                 //Cleans up output a bit for a better looking, HTML-safe output
 728:                 echo htmlentities(
 729:                     preg_replace('/[\r\n]+/', '', $str),
 730:                     ENT_QUOTES,
 731:                     'UTF-8'
 732:                 )
 733:                 . "<br>\n";
 734:                 break;
 735:             case 'echo':
 736:             default:
 737:                 //Normalize line breaks
 738:                 $str = preg_replace('/\r\n?/ms', "\n", $str);
 739:                 echo gmdate('Y-m-d H:i:s') . "\t" . str_replace(
 740:                     "\n",
 741:                     "\n                   \t                  ",
 742:                     trim($str)
 743:                 ) . "\n";
 744:         }
 745:     }
 746: 
 747:     /**
 748:      * Sets message type to HTML or plain.
 749:      * @param boolean $isHtml True for HTML mode.
 750:      * @return void
 751:      */
 752:     public function isHTML($isHtml = true)
 753:     {
 754:         if ($isHtml) {
 755:             $this->ContentType = 'text/html';
 756:         } else {
 757:             $this->ContentType = 'text/plain';
 758:         }
 759:     }
 760: 
 761:     /**
 762:      * Send messages using SMTP.
 763:      * @return void
 764:      */
 765:     public function isSMTP()
 766:     {
 767:         $this->Mailer = 'smtp';
 768:     }
 769: 
 770:     /**
 771:      * Send messages using PHP's mail() function.
 772:      * @return void
 773:      */
 774:     public function isMail()
 775:     {
 776:         $this->Mailer = 'mail';
 777:     }
 778: 
 779:     /**
 780:      * Send messages using $Sendmail.
 781:      * @return void
 782:      */
 783:     public function isSendmail()
 784:     {
 785:         $ini_sendmail_path = ini_get('sendmail_path');
 786: 
 787:         if (!stristr($ini_sendmail_path, 'sendmail')) {
 788:             $this->Sendmail = '/usr/sbin/sendmail';
 789:         } else {
 790:             $this->Sendmail = $ini_sendmail_path;
 791:         }
 792:         $this->Mailer = 'sendmail';
 793:     }
 794: 
 795:     /**
 796:      * Send messages using qmail.
 797:      * @return void
 798:      */
 799:     public function isQmail()
 800:     {
 801:         $ini_sendmail_path = ini_get('sendmail_path');
 802: 
 803:         if (!stristr($ini_sendmail_path, 'qmail')) {
 804:             $this->Sendmail = '/var/qmail/bin/qmail-inject';
 805:         } else {
 806:             $this->Sendmail = $ini_sendmail_path;
 807:         }
 808:         $this->Mailer = 'qmail';
 809:     }
 810: 
 811:     /**
 812:      * Add a "To" address.
 813:      * @param string $address The email address to send to
 814:      * @param string $name
 815:      * @return boolean true on success, false if address already used or invalid in some way
 816:      */
 817:     public function addAddress($address, $name = '')
 818:     {
 819:         return $this->addOrEnqueueAnAddress('to', $address, $name);
 820:     }
 821: 
 822:     /**
 823:      * Add a "CC" address.
 824:      * @note: This function works with the SMTP mailer on win32, not with the "mail" mailer.
 825:      * @param string $address The email address to send to
 826:      * @param string $name
 827:      * @return boolean true on success, false if address already used or invalid in some way
 828:      */
 829:     public function addCC($address, $name = '')
 830:     {
 831:         return $this->addOrEnqueueAnAddress('cc', $address, $name);
 832:     }
 833: 
 834:     /**
 835:      * Add a "BCC" address.
 836:      * @note: This function works with the SMTP mailer on win32, not with the "mail" mailer.
 837:      * @param string $address The email address to send to
 838:      * @param string $name
 839:      * @return boolean true on success, false if address already used or invalid in some way
 840:      */
 841:     public function addBCC($address, $name = '')
 842:     {
 843:         return $this->addOrEnqueueAnAddress('bcc', $address, $name);
 844:     }
 845: 
 846:     /**
 847:      * Add a "Reply-To" address.
 848:      * @param string $address The email address to reply to
 849:      * @param string $name
 850:      * @return boolean true on success, false if address already used or invalid in some way
 851:      */
 852:     public function addReplyTo($address, $name = '')
 853:     {
 854:         return $this->addOrEnqueueAnAddress('Reply-To', $address, $name);
 855:     }
 856: 
 857:     /**
 858:      * Add an address to one of the recipient arrays or to the ReplyTo array. Because PHPMailer
 859:      * can't validate addresses with an IDN without knowing the PHPMailer::$CharSet (that can still
 860:      * be modified after calling this function), addition of such addresses is delayed until send().
 861:      * Addresses that have been added already return false, but do not throw exceptions.
 862:      * @param string $kind One of 'to', 'cc', 'bcc', or 'ReplyTo'
 863:      * @param string $address The email address to send, resp. to reply to
 864:      * @param string $name
 865:      * @throws phpmailerException
 866:      * @return boolean true on success, false if address already used or invalid in some way
 867:      * @access protected
 868:      */
 869:     protected function addOrEnqueueAnAddress($kind, $address, $name)
 870:     {
 871:         $address = trim($address);
 872:         $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim
 873:         if (($pos = strrpos($address, '@')) === false) {
 874:             // At-sign is misssing.
 875:             $error_message = $this->lang('invalid_address') . " (addAnAddress $kind): $address";
 876:             $this->setError($error_message);
 877:             $this->edebug($error_message);
 878:             if ($this->exceptions) {
 879:                 throw new phpmailerException($error_message);
 880:             }
 881:             return false;
 882:         }
 883:         $params = array($kind, $address, $name);
 884:         // Enqueue addresses with IDN until we know the PHPMailer::$CharSet.
 885:         if ($this->has8bitChars(substr($address, ++$pos)) and $this->idnSupported()) {
 886:             if ($kind != 'Reply-To') {
 887:                 if (!array_key_exists($address, $this->RecipientsQueue)) {
 888:                     $this->RecipientsQueue[$address] = $params;
 889:                     return true;
 890:                 }
 891:             } else {
 892:                 if (!array_key_exists($address, $this->ReplyToQueue)) {
 893:                     $this->ReplyToQueue[$address] = $params;
 894:                     return true;
 895:                 }
 896:             }
 897:             return false;
 898:         }
 899:         // Immediately add standard addresses without IDN.
 900:         return call_user_func_array(array($this, 'addAnAddress'), $params);
 901:     }
 902: 
 903:     /**
 904:      * Add an address to one of the recipient arrays or to the ReplyTo array.
 905:      * Addresses that have been added already return false, but do not throw exceptions.
 906:      * @param string $kind One of 'to', 'cc', 'bcc', or 'ReplyTo'
 907:      * @param string $address The email address to send, resp. to reply to
 908:      * @param string $name
 909:      * @throws phpmailerException
 910:      * @return boolean true on success, false if address already used or invalid in some way
 911:      * @access protected
 912:      */
 913:     protected function addAnAddress($kind, $address, $name = '')
 914:     {
 915:         if (!in_array($kind, array('to', 'cc', 'bcc', 'Reply-To'))) {
 916:             $error_message = $this->lang('Invalid recipient kind: ') . $kind;
 917:             $this->setError($error_message);
 918:             $this->edebug($error_message);
 919:             if ($this->exceptions) {
 920:                 throw new phpmailerException($error_message);
 921:             }
 922:             return false;
 923:         }
 924:         if (!$this->validateAddress($address)) {
 925:             $error_message = $this->lang('invalid_address') . " (addAnAddress $kind): $address";
 926:             $this->setError($error_message);
 927:             $this->edebug($error_message);
 928:             if ($this->exceptions) {
 929:                 throw new phpmailerException($error_message);
 930:             }
 931:             return false;
 932:         }
 933:         if ($kind != 'Reply-To') {
 934:             if (!array_key_exists(strtolower($address), $this->all_recipients)) {
 935:                 array_push($this->$kind, array($address, $name));
 936:                 $this->all_recipients[strtolower($address)] = true;
 937:                 return true;
 938:             }
 939:         } else {
 940:             if (!array_key_exists(strtolower($address), $this->ReplyTo)) {
 941:                 $this->ReplyTo[strtolower($address)] = array($address, $name);
 942:                 return true;
 943:             }
 944:         }
 945:         return false;
 946:     }
 947: 
 948:     /**
 949:      * Parse and validate a string containing one or more RFC822-style comma-separated email addresses
 950:      * of the form "display name <address>" into an array of name/address pairs.
 951:      * Uses the imap_rfc822_parse_adrlist function if the IMAP extension is available.
 952:      * Note that quotes in the name part are removed.
 953:      * @param string $addrstr The address list string
 954:      * @param bool $useimap Whether to use the IMAP extension to parse the list
 955:      * @return array
 956:      * @link http://www.andrew.cmu.edu/user/agreen1/testing/mrbs/web/Mail/RFC822.php A more careful implementation
 957:      */
 958:     public function parseAddresses($addrstr, $useimap = true)
 959:     {
 960:         $addresses = array();
 961:         if ($useimap and function_exists('imap_rfc822_parse_adrlist')) {
 962:             //Use this built-in parser if it's available
 963:             $list = imap_rfc822_parse_adrlist($addrstr, '');
 964:             foreach ($list as $address) {
 965:                 if ($address->host != '.SYNTAX-ERROR.') {
 966:                     if ($this->validateAddress($address->mailbox . '@' . $address->host)) {
 967:                         $addresses[] = array(
 968:                             'name' => (property_exists($address, 'personal') ? $address->personal : ''),
 969:                             'address' => $address->mailbox . '@' . $address->host
 970:                         );
 971:                     }
 972:                 }
 973:             }
 974:         } else {
 975:             //Use this simpler parser
 976:             $list = explode(',', $addrstr);
 977:             foreach ($list as $address) {
 978:                 $address = trim($address);
 979:                 //Is there a separate name part?
 980:                 if (strpos($address, '<') === false) {
 981:                     //No separate name, just use the whole thing
 982:                     if ($this->validateAddress($address)) {
 983:                         $addresses[] = array(
 984:                             'name' => '',
 985:                             'address' => $address
 986:                         );
 987:                     }
 988:                 } else {
 989:                     list($name, $email) = explode('<', $address);
 990:                     $email = trim(str_replace('>', '', $email));
 991:                     if ($this->validateAddress($email)) {
 992:                         $addresses[] = array(
 993:                             'name' => trim(str_replace(array('"', "'"), '', $name)),
 994:                             'address' => $email
 995:                         );
 996:                     }
 997:                 }
 998:             }
 999:         }
1000:         return $addresses;
1001:     }
1002: 
1003:     /**
1004:      * Set the From and FromName properties.
1005:      * @param string $address
1006:      * @param string $name
1007:      * @param boolean $auto Whether to also set the Sender address, defaults to true
1008:      * @throws phpmailerException
1009:      * @return boolean
1010:      */
1011:     public function setFrom($address, $name = '', $auto = true)
1012:     {
1013:         $address = trim($address);
1014:         $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim
1015:         // Don't validate now addresses with IDN. Will be done in send().
1016:         if (($pos = strrpos($address, '@')) === false or
1017:             (!$this->has8bitChars(substr($address, ++$pos)) or !$this->idnSupported()) and
1018:             !$this->validateAddress($address)) {
1019:             $error_message = $this->lang('invalid_address') . " (setFrom) $address";
1020:             $this->setError($error_message);
1021:             $this->edebug($error_message);
1022:             if ($this->exceptions) {
1023:                 throw new phpmailerException($error_message);
1024:             }
1025:             return false;
1026:         }
1027:         $this->From = $address;
1028:         $this->FromName = $name;
1029:         if ($auto) {
1030:             if (empty($this->Sender)) {
1031:                 $this->Sender = $address;
1032:             }
1033:         }
1034:         return true;
1035:     }
1036: 
1037:     /**
1038:      * Return the Message-ID header of the last email.
1039:      * Technically this is the value from the last time the headers were created,
1040:      * but it's also the message ID of the last sent message except in
1041:      * pathological cases.
1042:      * @return string
1043:      */
1044:     public function getLastMessageID()
1045:     {
1046:         return $this->lastMessageID;
1047:     }
1048: 
1049:     /**
1050:      * Check that a string looks like an email address.
1051:      * @param string $address The email address to check
1052:      * @param string|callable $patternselect A selector for the validation pattern to use :
1053:      * * `auto` Pick best pattern automatically;
1054:      * * `pcre8` Use the squiloople.com pattern, requires PCRE > 8.0, PHP >= 5.3.2, 5.2.14;
1055:      * * `pcre` Use old PCRE implementation;
1056:      * * `php` Use PHP built-in FILTER_VALIDATE_EMAIL;
1057:      * * `html5` Use the pattern given by the HTML5 spec for 'email' type form input elements.
1058:      * * `noregex` Don't use a regex: super fast, really dumb.
1059:      * Alternatively you may pass in a callable to inject your own validator, for example:
1060:      * PHPMailer::validateAddress('user@example.com', function($address) {
1061:      *     return (strpos($address, '@') !== false);
1062:      * });
1063:      * You can also set the PHPMailer::$validator static to a callable, allowing built-in methods to use your validator.
1064:      * @return boolean
1065:      * @static
1066:      * @access public
1067:      */
1068:     public static function validateAddress($address, $patternselect = null)
1069:     {
1070:         if (is_null($patternselect)) {
1071:             $patternselect = self::$validator;
1072:         }
1073:         if (is_callable($patternselect)) {
1074:             return call_user_func($patternselect, $address);
1075:         }
1076:         //Reject line breaks in addresses; it's valid RFC5322, but not RFC5321
1077:         if (strpos($address, "\n") !== false or strpos($address, "\r") !== false) {
1078:             return false;
1079:         }
1080:         if (!$patternselect or $patternselect == 'auto') {
1081:             //Check this constant first so it works when extension_loaded() is disabled by safe mode
1082:             //Constant was added in PHP 5.2.4
1083:             if (defined('PCRE_VERSION')) {
1084:                 //This pattern can get stuck in a recursive loop in PCRE <= 8.0.2
1085:                 if (version_compare(PCRE_VERSION, '8.0.3') >= 0) {
1086:                     $patternselect = 'pcre8';
1087:                 } else {
1088:                     $patternselect = 'pcre';
1089:                 }
1090:             } elseif (function_exists('extension_loaded') and extension_loaded('pcre')) {
1091:                 //Fall back to older PCRE
1092:                 $patternselect = 'pcre';
1093:             } else {
1094:                 //Filter_var appeared in PHP 5.2.0 and does not require the PCRE extension
1095:                 if (version_compare(PHP_VERSION, '5.2.0') >= 0) {
1096:                     $patternselect = 'php';
1097:                 } else {
1098:                     $patternselect = 'noregex';
1099:                 }
1100:             }
1101:         }
1102:         switch ($patternselect) {
1103:             case 'pcre8':
1104:                 /**
1105:                  * Uses the same RFC5322 regex on which FILTER_VALIDATE_EMAIL is based, but allows dotless domains.
1106:                  * @link http://squiloople.com/2009/12/20/email-address-validation/
1107:                  * @copyright 2009-2010 Michael Rushton
1108:                  * Feel free to use and redistribute this code. But please keep this copyright notice.
1109:                  */
1110:                 return (boolean)preg_match(
1111:                     '/^(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){255,})(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){65,}@)' .
1112:                     '((?>(?>(?>((?>(?>(?>\x0D\x0A)?[\t ])+|(?>[\t ]*\x0D\x0A)?[\t ]+)?)(\((?>(?2)' .
1113:                     '(?>[\x01-\x08\x0B\x0C\x0E-\'*-\[\]-\x7F]|\\\[\x00-\x7F]|(?3)))*(?2)\)))+(?2))|(?2))?)' .
1114:                     '([!#-\'*+\/-9=?^-~-]+|"(?>(?2)(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\x7F]))*' .
1115:                     '(?2)")(?>(?1)\.(?1)(?4))*(?1)@(?!(?1)[a-z0-9-]{64,})(?1)(?>([a-z0-9](?>[a-z0-9-]*[a-z0-9])?)' .
1116:                     '(?>(?1)\.(?!(?1)[a-z0-9-]{64,})(?1)(?5)){0,126}|\[(?:(?>IPv6:(?>([a-f0-9]{1,4})(?>:(?6)){7}' .
1117:                     '|(?!(?:.*[a-f0-9][:\]]){8,})((?6)(?>:(?6)){0,6})?::(?7)?))|(?>(?>IPv6:(?>(?6)(?>:(?6)){5}:' .
1118:                     '|(?!(?:.*[a-f0-9]:){6,})(?8)?::(?>((?6)(?>:(?6)){0,4}):)?))?(25[0-5]|2[0-4][0-9]|1[0-9]{2}' .
1119:                     '|[1-9]?[0-9])(?>\.(?9)){3}))\])(?1)$/isD',
1120:                     $address
1121:                 );
1122:             case 'pcre':
1123:                 //An older regex that doesn't need a recent PCRE
1124:                 return (boolean)preg_match(
1125:                     '/^(?!(?>"?(?>\\\[ -~]|[^"])"?){255,})(?!(?>"?(?>\\\[ -~]|[^"])"?){65,}@)(?>' .
1126:                     '[!#-\'*+\/-9=?^-~-]+|"(?>(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\xFF]))*")' .
1127:                     '(?>\.(?>[!#-\'*+\/-9=?^-~-]+|"(?>(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\xFF]))*"))*' .
1128:                     '@(?>(?![a-z0-9-]{64,})(?>[a-z0-9](?>[a-z0-9-]*[a-z0-9])?)(?>\.(?![a-z0-9-]{64,})' .
1129:                     '(?>[a-z0-9](?>[a-z0-9-]*[a-z0-9])?)){0,126}|\[(?:(?>IPv6:(?>(?>[a-f0-9]{1,4})(?>:' .
1130:                     '[a-f0-9]{1,4}){7}|(?!(?:.*[a-f0-9][:\]]){8,})(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,6})?' .
1131:                     '::(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,6})?))|(?>(?>IPv6:(?>[a-f0-9]{1,4}(?>:' .
1132:                     '[a-f0-9]{1,4}){5}:|(?!(?:.*[a-f0-9]:){6,})(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,4})?' .
1133:                     '::(?>(?:[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,4}):)?))?(?>25[0-5]|2[0-4][0-9]|1[0-9]{2}' .
1134:                     '|[1-9]?[0-9])(?>\.(?>25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}))\])$/isD',
1135:                     $address
1136:                 );
1137:             case 'html5':
1138:                 /**
1139:                  * This is the pattern used in the HTML5 spec for validation of 'email' type form input elements.
1140:                  * @link http://www.whatwg.org/specs/web-apps/current-work/#e-mail-state-(type=email)
1141:                  */
1142:                 return (boolean)preg_match(
1143:                     '/^[a-zA-Z0-9.!#$%&\'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}' .
1144:                     '[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/sD',
1145:                     $address
1146:                 );
1147:             case 'noregex':
1148:                 //No PCRE! Do something _very_ approximate!
1149:                 //Check the address is 3 chars or longer and contains an @ that's not the first or last char
1150:                 return (strlen($address) >= 3
1151:                     and strpos($address, '@') >= 1
1152:                     and strpos($address, '@') != strlen($address) - 1);
1153:             case 'php':
1154:             default:
1155:                 return (boolean)filter_var($address, FILTER_VALIDATE_EMAIL);
1156:         }
1157:     }
1158: 
1159:     /**
1160:      * Tells whether IDNs (Internationalized Domain Names) are supported or not. This requires the
1161:      * "intl" and "mbstring" PHP extensions.
1162:      * @return bool "true" if required functions for IDN support are present
1163:      */
1164:     public function idnSupported()
1165:     {
1166:         // @TODO: Write our own "idn_to_ascii" function for PHP <= 5.2.
1167:         return function_exists('idn_to_ascii') and function_exists('mb_convert_encoding');
1168:     }
1169: 
1170:     /**
1171:      * Converts IDN in given email address to its ASCII form, also known as punycode, if possible.
1172:      * Important: Address must be passed in same encoding as currently set in PHPMailer::$CharSet.
1173:      * This function silently returns unmodified address if:
1174:      * - No conversion is necessary (i.e. domain name is not an IDN, or is already in ASCII form)
1175:      * - Conversion to punycode is impossible (e.g. required PHP functions are not available)
1176:      *   or fails for any reason (e.g. domain has characters not allowed in an IDN)
1177:      * @see PHPMailer::$CharSet
1178:      * @param string $address The email address to convert
1179:      * @return string The encoded address in ASCII form
1180:      */
1181:     public function punyencodeAddress($address)
1182:     {
1183:         // Verify we have required functions, CharSet, and at-sign.
1184:         if ($this->idnSupported() and
1185:             !empty($this->CharSet) and
1186:             ($pos = strrpos($address, '@')) !== false) {
1187:             $domain = substr($address, ++$pos);
1188:             // Verify CharSet string is a valid one, and domain properly encoded in this CharSet.
1189:             if ($this->has8bitChars($domain) and @mb_check_encoding($domain, $this->CharSet)) {
1190:                 $domain = mb_convert_encoding($domain, 'UTF-8', $this->CharSet);
1191:                 if (($punycode = defined('INTL_IDNA_VARIANT_UTS46') ?
1192:                     idn_to_ascii($domain, 0, INTL_IDNA_VARIANT_UTS46) :
1193:                     idn_to_ascii($domain)) !== false) {
1194:                     return substr($address, 0, $pos) . $punycode;
1195:                 }
1196:             }
1197:         }
1198:         return $address;
1199:     }
1200: 
1201:     /**
1202:      * Create a message and send it.
1203:      * Uses the sending method specified by $Mailer.
1204:      * @throws phpmailerException
1205:      * @return boolean false on error - See the ErrorInfo property for details of the error.
1206:      */
1207:     public function send()
1208:     {
1209:         try {
1210:             if (!$this->preSend()) {
1211:                 return false;
1212:             }
1213:             return $this->postSend();
1214:         } catch (phpmailerException $exc) {
1215:             $this->mailHeader = '';
1216:             $this->setError($exc->getMessage());
1217:             if ($this->exceptions) {
1218:                 throw $exc;
1219:             }
1220:             return false;
1221:         }
1222:     }
1223: 
1224:     /**
1225:      * Prepare a message for sending.
1226:      * @throws phpmailerException
1227:      * @return boolean
1228:      */
1229:     public function preSend()
1230:     {
1231:         try {
1232:             $this->error_count = 0; // Reset errors
1233:             $this->mailHeader = '';
1234: 
1235:             // Dequeue recipient and Reply-To addresses with IDN
1236:             foreach (array_merge($this->RecipientsQueue, $this->ReplyToQueue) as $params) {
1237:                 $params[1] = $this->punyencodeAddress($params[1]);
1238:                 call_user_func_array(array($this, 'addAnAddress'), $params);
1239:             }
1240:             if ((count($this->to) + count($this->cc) + count($this->bcc)) < 1) {
1241:                 throw new phpmailerException($this->lang('provide_address'), self::STOP_CRITICAL);
1242:             }
1243: 
1244:             // Validate From, Sender, and ConfirmReadingTo addresses
1245:             foreach (array('From', 'Sender', 'ConfirmReadingTo') as $address_kind) {
1246:                 $this->$address_kind = trim($this->$address_kind);
1247:                 if (empty($this->$address_kind)) {
1248:                     continue;
1249:                 }
1250:                 $this->$address_kind = $this->punyencodeAddress($this->$address_kind);
1251:                 if (!$this->validateAddress($this->$address_kind)) {
1252:                     $error_message = $this->lang('invalid_address') . ' (punyEncode) ' . $this->$address_kind;
1253:                     $this->setError($error_message);
1254:                     $this->edebug($error_message);
1255:                     if ($this->exceptions) {
1256:                         throw new phpmailerException($error_message);
1257:                     }
1258:                     return false;
1259:                 }
1260:             }
1261: 
1262:             // Set whether the message is multipart/alternative
1263:             if ($this->alternativeExists()) {
1264:                 $this->ContentType = 'multipart/alternative';
1265:             }
1266: 
1267:             $this->setMessageType();
1268:             // Refuse to send an empty message unless we are specifically allowing it
1269:             if (!$this->AllowEmpty and empty($this->Body)) {
1270:                 throw new phpmailerException($this->lang('empty_message'), self::STOP_CRITICAL);
1271:             }
1272: 
1273:             // Create body before headers in case body makes changes to headers (e.g. altering transfer encoding)
1274:             $this->MIMEHeader = '';
1275:             $this->MIMEBody = $this->createBody();
1276:             // createBody may have added some headers, so retain them
1277:             $tempheaders = $this->MIMEHeader;
1278:             $this->MIMEHeader = $this->createHeader();
1279:             $this->MIMEHeader .= $tempheaders;
1280: 
1281:             // To capture the complete message when using mail(), create
1282:             // an extra header list which createHeader() doesn't fold in
1283:             if ($this->Mailer == 'mail') {
1284:                 if (count($this->to) > 0) {
1285:                     $this->mailHeader .= $this->addrAppend('To', $this->to);
1286:                 } else {
1287:                     $this->mailHeader .= $this->headerLine('To', 'undisclosed-recipients:;');
1288:                 }
1289:                 $this->mailHeader .= $this->headerLine(
1290:                     'Subject',
1291:                     $this->encodeHeader($this->secureHeader(trim($this->Subject)))
1292:                 );
1293:             }
1294: 
1295:             // Sign with DKIM if enabled
1296:             if (!empty($this->DKIM_domain)
1297:                 && !empty($this->DKIM_selector)
1298:                 && (!empty($this->DKIM_private_string)
1299:                    || (!empty($this->DKIM_private) && file_exists($this->DKIM_private))
1300:                 )
1301:             ) {
1302:                 $header_dkim = $this->DKIM_Add(
1303:                     $this->MIMEHeader . $this->mailHeader,
1304:                     $this->encodeHeader($this->secureHeader($this->Subject)),
1305:                     $this->MIMEBody
1306:                 );
1307:                 $this->MIMEHeader = rtrim($this->MIMEHeader, "\r\n ") . self::CRLF .
1308:                     str_replace("\r\n", "\n", $header_dkim) . self::CRLF;
1309:             }
1310:             return true;
1311:         } catch (phpmailerException $exc) {
1312:             $this->setError($exc->getMessage());
1313:             if ($this->exceptions) {
1314:                 throw $exc;
1315:             }
1316:             return false;
1317:         }
1318:     }
1319: 
1320:     /**
1321:      * Actually send a message.
1322:      * Send the email via the selected mechanism
1323:      * @throws phpmailerException
1324:      * @return boolean
1325:      */
1326:     public function postSend()
1327:     {
1328:         try {
1329:             // Choose the mailer and send through it
1330:             switch ($this->Mailer) {
1331:                 case 'sendmail':
1332:                 case 'qmail':
1333:                     return $this->sendmailSend($this->MIMEHeader, $this->MIMEBody);
1334:                 case 'smtp':
1335:                     return $this->smtpSend($this->MIMEHeader, $this->MIMEBody);
1336:                 case 'mail':
1337:                     return $this->mailSend($this->MIMEHeader, $this->MIMEBody);
1338:                 default:
1339:                     $sendMethod = $this->Mailer.'Send';
1340:                     if (method_exists($this, $sendMethod)) {
1341:                         return $this->$sendMethod($this->MIMEHeader, $this->MIMEBody);
1342:                     }
1343: 
1344:                     return $this->mailSend($this->MIMEHeader, $this->MIMEBody);
1345:             }
1346:         } catch (phpmailerException $exc) {
1347:             $this->setError($exc->getMessage());
1348:             $this->edebug($exc->getMessage());
1349:             if ($this->exceptions) {
1350:                 throw $exc;
1351:             }
1352:         }
1353:         return false;
1354:     }
1355: 
1356:     /**
1357:      * Send mail using the $Sendmail program.
1358:      * @param string $header The message headers
1359:      * @param string $body The message body
1360:      * @see PHPMailer::$Sendmail
1361:      * @throws phpmailerException
1362:      * @access protected
1363:      * @return boolean
1364:      */
1365:     protected function sendmailSend($header, $body)
1366:     {
1367:         // CVE-2016-10033, CVE-2016-10045: Don't pass -f if characters will be escaped.
1368:         if (!empty($this->Sender) and self::isShellSafe($this->Sender)) {
1369:             if ($this->Mailer == 'qmail') {
1370:                 $sendmailFmt = '%s -f%s';
1371:             } else {
1372:                 $sendmailFmt = '%s -oi -f%s -t';
1373:             }
1374:         } else {
1375:             if ($this->Mailer == 'qmail') {
1376:                 $sendmailFmt = '%s';
1377:             } else {
1378:                 $sendmailFmt = '%s -oi -t';
1379:             }
1380:         }
1381: 
1382:         // TODO: If possible, this should be changed to escapeshellarg.  Needs thorough testing.
1383:         $sendmail = sprintf($sendmailFmt, escapeshellcmd($this->Sendmail), $this->Sender);
1384: 
1385:         if ($this->SingleTo) {
1386:             foreach ($this->SingleToArray as $toAddr) {
1387:                 if (!@$mail = popen($sendmail, 'w')) {
1388:                     throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
1389:                 }
1390:                 fputs($mail, 'To: ' . $toAddr . "\n");
1391:                 fputs($mail, $header);
1392:                 fputs($mail, $body);
1393:                 $result = pclose($mail);
1394:                 $this->doCallback(
1395:                     ($result == 0),
1396:                     array($toAddr),
1397:                     $this->cc,
1398:                     $this->bcc,
1399:                     $this->Subject,
1400:                     $body,
1401:                     $this->From
1402:                 );
1403:                 if ($result != 0) {
1404:                     throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
1405:                 }
1406:             }
1407:         } else {
1408:             if (!@$mail = popen($sendmail, 'w')) {
1409:                 throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
1410:             }
1411:             fputs($mail, $header);
1412:             fputs($mail, $body);
1413:             $result = pclose($mail);
1414:             $this->doCallback(
1415:                 ($result == 0),
1416:                 $this->to,
1417:                 $this->cc,
1418:                 $this->bcc,
1419:                 $this->Subject,
1420:                 $body,
1421:                 $this->From
1422:             );
1423:             if ($result != 0) {
1424:                 throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
1425:             }
1426:         }
1427:         return true;
1428:     }
1429: 
1430:     /**
1431:      * Fix CVE-2016-10033 and CVE-2016-10045 by disallowing potentially unsafe shell characters.
1432:      *
1433:      * Note that escapeshellarg and escapeshellcmd are inadequate for our purposes, especially on Windows.
1434:      * @param string $string The string to be validated
1435:      * @see https://github.com/PHPMailer/PHPMailer/issues/924 CVE-2016-10045 bug report
1436:      * @access protected
1437:      * @return boolean
1438:      */
1439:     protected static function isShellSafe($string)
1440:     {
1441:         // Future-proof
1442:         if (escapeshellcmd($string) !== $string
1443:             or !in_array(escapeshellarg($string), array("'$string'", "\"$string\""))
1444:         ) {
1445:             return false;
1446:         }
1447: 
1448:         $length = strlen($string);
1449: 
1450:         for ($i = 0; $i < $length; $i++) {
1451:             $c = $string[$i];
1452: 
1453:             // All other characters have a special meaning in at least one common shell, including = and +.
1454:             // Full stop (.) has a special meaning in cmd.exe, but its impact should be negligible here.
1455:             // Note that this does permit non-Latin alphanumeric characters based on the current locale.
1456:             if (!ctype_alnum($c) && strpos('@_-.', $c) === false) {
1457:                 return false;
1458:             }
1459:         }
1460: 
1461:         return true;
1462:     }
1463: 
1464:     /**
1465:      * Send mail using the PHP mail() function.
1466:      * @param string $header The message headers
1467:      * @param string $body The message body
1468:      * @link http://www.php.net/manual/en/book.mail.php
1469:      * @throws phpmailerException
1470:      * @access protected
1471:      * @return boolean
1472:      */
1473:     protected function mailSend($header, $body)
1474:     {
1475:         $toArr = array();
1476:         foreach ($this->to as $toaddr) {
1477:             $toArr[] = $this->addrFormat($toaddr);
1478:         }
1479:         $to = implode(', ', $toArr);
1480: 
1481:         $params = null;
1482:         //This sets the SMTP envelope sender which gets turned into a return-path header by the receiver
1483:         if (!empty($this->Sender) and $this->validateAddress($this->Sender)) {
1484:             // CVE-2016-10033, CVE-2016-10045: Don't pass -f if characters will be escaped.
1485:             if (self::isShellSafe($this->Sender)) {
1486:                 $params = sprintf('-f%s', $this->Sender);
1487:             }
1488:         }
1489:         if (!empty($this->Sender) and !ini_get('safe_mode') and $this->validateAddress($this->Sender)) {
1490:             $old_from = ini_get('sendmail_from');
1491:             ini_set('sendmail_from', $this->Sender);
1492:         }
1493:         $result = false;
1494:         if ($this->SingleTo and count($toArr) > 1) {
1495:             foreach ($toArr as $toAddr) {
1496:                 $result = $this->mailPassthru($toAddr, $this->Subject, $body, $header, $params);
1497:                 $this->doCallback($result, array($toAddr), $this->cc, $this->bcc, $this->Subject, $body, $this->From);
1498:             }
1499:         } else {
1500:             $result = $this->mailPassthru($to, $this->Subject, $body, $header, $params);
1501:             $this->doCallback($result, $this->to, $this->cc, $this->bcc, $this->Subject, $body, $this->From);
1502:         }
1503:         if (isset($old_from)) {
1504:             ini_set('sendmail_from', $old_from);
1505:         }
1506:         if (!$result) {
1507:             throw new phpmailerException($this->lang('instantiate'), self::STOP_CRITICAL);
1508:         }
1509:         return true;
1510:     }
1511: 
1512:     /**
1513:      * Get an instance to use for SMTP operations.
1514:      * Override this function to load your own SMTP implementation
1515:      * @return SMTP
1516:      */
1517:     public function getSMTPInstance()
1518:     {
1519:         if (!is_object($this->smtp)) {
1520:             $this->smtp = new SMTP;
1521:         }
1522:         return $this->smtp;
1523:     }
1524: 
1525:     /**
1526:      * Send mail via SMTP.
1527:      * Returns false if there is a bad MAIL FROM, RCPT, or DATA input.
1528:      * Uses the PHPMailerSMTP class by default.
1529:      * @see PHPMailer::getSMTPInstance() to use a different class.
1530:      * @param string $header The message headers
1531:      * @param string $body The message body
1532:      * @throws phpmailerException
1533:      * @uses SMTP
1534:      * @access protected
1535:      * @return boolean
1536:      */
1537:     protected function smtpSend($header, $body)
1538:     {
1539:         $bad_rcpt = array();
1540:         if (!$this->smtpConnect($this->SMTPOptions)) {
1541:             throw new phpmailerException($this->lang('smtp_connect_failed'), self::STOP_CRITICAL);
1542:         }
1543:         if (!empty($this->Sender) and $this->validateAddress($this->Sender)) {
1544:             $smtp_from = $this->Sender;
1545:         } else {
1546:             $smtp_from = $this->From;
1547:         }
1548:         if (!$this->smtp->mail($smtp_from)) {
1549:             $this->setError($this->lang('from_failed') . $smtp_from . ' : ' . implode(',', $this->smtp->getError()));
1550:             throw new phpmailerException($this->ErrorInfo, self::STOP_CRITICAL);
1551:         }
1552: 
1553:         // Attempt to send to all recipients
1554:         foreach (array($this->to, $this->cc, $this->bcc) as $togroup) {
1555:             foreach ($togroup as $to) {
1556:                 if (!$this->smtp->recipient($to[0])) {
1557:                     $error = $this->smtp->getError();
1558:                     $bad_rcpt[] = array('to' => $to[0], 'error' => $error['detail']);
1559:                     $isSent = false;
1560:                 } else {
1561:                     $isSent = true;
1562:                 }
1563:                 $this->doCallback($isSent, array($to[0]), array(), array(), $this->Subject, $body, $this->From);
1564:             }
1565:         }
1566: 
1567:         // Only send the DATA command if we have viable recipients
1568:         if ((count($this->all_recipients) > count($bad_rcpt)) and !$this->smtp->data($header . $body)) {
1569:             throw new phpmailerException($this->lang('data_not_accepted'), self::STOP_CRITICAL);
1570:         }
1571:         if ($this->SMTPKeepAlive) {
1572:             $this->smtp->reset();
1573:         } else {
1574:             $this->smtp->quit();
1575:             $this->smtp->close();
1576:         }
1577:         //Create error message for any bad addresses
1578:         if (count($bad_rcpt) > 0) {
1579:             $errstr = '';
1580:             foreach ($bad_rcpt as $bad) {
1581:                 $errstr .= $bad['to'] . ': ' . $bad['error'];
1582:             }
1583:             throw new phpmailerException(
1584:                 $this->lang('recipients_failed') . $errstr,
1585:                 self::STOP_CONTINUE
1586:             );
1587:         }
1588:         return true;
1589:     }
1590: 
1591:     /**
1592:      * Initiate a connection to an SMTP server.
1593:      * Returns false if the operation failed.
1594:      * @param array $options An array of options compatible with stream_context_create()
1595:      * @uses SMTP
1596:      * @access public
1597:      * @throws phpmailerException
1598:      * @return boolean
1599:      */
1600:     public function smtpConnect($options = null)
1601:     {
1602:         if (is_null($this->smtp)) {
1603:             $this->smtp = $this->getSMTPInstance();
1604:         }
1605: 
1606:         //If no options are provided, use whatever is set in the instance
1607:         if (is_null($options)) {
1608:             $options = $this->SMTPOptions;
1609:         }
1610: 
1611:         // Already connected?
1612:         if ($this->smtp->connected()) {
1613:             return true;
1614:         }
1615: 
1616:         $this->smtp->setTimeout($this->Timeout);
1617:         $this->smtp->setDebugLevel($this->SMTPDebug);
1618:         $this->smtp->setDebugOutput($this->Debugoutput);
1619:         $this->smtp->setVerp($this->do_verp);
1620:         $hosts = explode(';', $this->Host);
1621:         $lastexception = null;
1622: 
1623:         foreach ($hosts as $hostentry) {
1624:             $hostinfo = array();
1625:             if (!preg_match('/^((ssl|tls):\/\/)*([a-zA-Z0-9\.-]*):?([0-9]*)$/', trim($hostentry), $hostinfo)) {
1626:                 // Not a valid host entry
1627:                 continue;
1628:             }
1629:             // $hostinfo[2]: optional ssl or tls prefix
1630:             // $hostinfo[3]: the hostname
1631:             // $hostinfo[4]: optional port number
1632:             // The host string prefix can temporarily override the current setting for SMTPSecure
1633:             // If it's not specified, the default value is used
1634:             $prefix = '';
1635:             $secure = $this->SMTPSecure;
1636:             $tls = ($this->SMTPSecure == 'tls');
1637:             if ('ssl' == $hostinfo[2] or ('' == $hostinfo[2] and 'ssl' == $this->SMTPSecure)) {
1638:                 $prefix = 'ssl://';
1639:                 $tls = false; // Can't have SSL and TLS at the same time
1640:                 $secure = 'ssl';
1641:             } elseif ($hostinfo[2] == 'tls') {
1642:                 $tls = true;
1643:                 // tls doesn't use a prefix
1644:                 $secure = 'tls';
1645:             }
1646:             //Do we need the OpenSSL extension?
1647:             $sslext = defined('OPENSSL_ALGO_SHA1');
1648:             if ('tls' === $secure or 'ssl' === $secure) {
1649:                 //Check for an OpenSSL constant rather than using extension_loaded, which is sometimes disabled
1650:                 if (!$sslext) {
1651:                     throw new phpmailerException($this->lang('extension_missing').'openssl', self::STOP_CRITICAL);
1652:                 }
1653:             }
1654:             $host = $hostinfo[3];
1655:             $port = $this->Port;
1656:             $tport = (integer)$hostinfo[4];
1657:             if ($tport > 0 and $tport < 65536) {
1658:                 $port = $tport;
1659:             }
1660:             if ($this->smtp->connect($prefix . $host, $port, $this->Timeout, $options)) {
1661:                 try {
1662:                     if ($this->Helo) {
1663:                         $hello = $this->Helo;
1664:                     } else {
1665:                         $hello = $this->serverHostname();
1666:                     }
1667:                     $this->smtp->hello($hello);
1668:                     //Automatically enable TLS encryption if:
1669:                     // * it's not disabled
1670:                     // * we have openssl extension
1671:                     // * we are not already using SSL
1672:                     // * the server offers STARTTLS
1673:                     if ($this->SMTPAutoTLS and $sslext and $secure != 'ssl' and $this->smtp->getServerExt('STARTTLS')) {
1674:                         $tls = true;
1675:                     }
1676:                     if ($tls) {
1677:                         if (!$this->smtp->startTLS()) {
1678:                             throw new phpmailerException($this->lang('connect_host'));
1679:                         }
1680:                         // We must resend EHLO after TLS negotiation
1681:                         $this->smtp->hello($hello);
1682:                     }
1683:                     if ($this->SMTPAuth) {
1684:                         if (!$this->smtp->authenticate(
1685:                             $this->Username,
1686:                             $this->Password,
1687:                             $this->AuthType,
1688:                             $this->Realm,
1689:                             $this->Workstation
1690:                         )
1691:                         ) {
1692:                             throw new phpmailerException($this->lang('authenticate'));
1693:                         }
1694:                     }
1695:                     return true;
1696:                 } catch (phpmailerException $exc) {
1697:                     $lastexception = $exc;
1698:                     $this->edebug($exc->getMessage());
1699:                     // We must have connected, but then failed TLS or Auth, so close connection nicely
1700:                     $this->smtp->quit();
1701:                 }
1702:             }
1703:         }
1704:         // If we get here, all connection attempts have failed, so close connection hard
1705:         $this->smtp->close();
1706:         // As we've caught all exceptions, just report whatever the last one was
1707:         if ($this->exceptions and !is_null($lastexception)) {
1708:             throw $lastexception;
1709:         }
1710:         return false;
1711:     }
1712: 
1713:     /**
1714:      * Close the active SMTP session if one exists.
1715:      * @return void
1716:      */
1717:     public function smtpClose()
1718:     {
1719:         if (is_a($this->smtp, 'SMTP')) {
1720:             if ($this->smtp->connected()) {
1721:                 $this->smtp->quit();
1722:                 $this->smtp->close();
1723:             }
1724:         }
1725:     }
1726: 
1727:     /**
1728:      * Set the language for error messages.
1729:      * Returns false if it cannot load the language file.
1730:      * The default language is English.
1731:      * @param string $langcode ISO 639-1 2-character language code (e.g. French is "fr")
1732:      * @param string $lang_path Path to the language file directory, with trailing separator (slash)
1733:      * @return boolean
1734:      * @access public
1735:      */
1736:     public function setLanguage($langcode = 'en', $lang_path = '')
1737:     {
1738:         // Backwards compatibility for renamed language codes
1739:         $renamed_langcodes = array(
1740:             'br' => 'pt_br',
1741:             'cz' => 'cs',
1742:             'dk' => 'da',
1743:             'no' => 'nb',
1744:             'se' => 'sv',
1745:         );
1746: 
1747:         if (isset($renamed_langcodes[$langcode])) {
1748:             $langcode = $renamed_langcodes[$langcode];
1749:         }
1750: 
1751:         // Define full set of translatable strings in English
1752:         $PHPMAILER_LANG = array(
1753:             'authenticate' => 'SMTP Error: Could not authenticate.',
1754:             'connect_host' => 'SMTP Error: Could not connect to SMTP host.',
1755:             'data_not_accepted' => 'SMTP Error: data not accepted.',
1756:             'empty_message' => 'Message body empty',
1757:             'encoding' => 'Unknown encoding: ',
1758:             'execute' => 'Could not execute: ',
1759:             'file_access' => 'Could not access file: ',
1760:             'file_open' => 'File Error: Could not open file: ',
1761:             'from_failed' => 'The following From address failed: ',
1762:             'instantiate' => 'Could not instantiate mail function.',
1763:             'invalid_address' => 'Invalid address: ',
1764:             'mailer_not_supported' => ' mailer is not supported.',
1765:             'provide_address' => 'You must provide at least one recipient email address.',
1766:             'recipients_failed' => 'SMTP Error: The following recipients failed: ',
1767:             'signing' => 'Signing Error: ',
1768:             'smtp_connect_failed' => 'SMTP connect() failed.',
1769:             'smtp_error' => 'SMTP server error: ',
1770:             'variable_set' => 'Cannot set or reset variable: ',
1771:             'extension_missing' => 'Extension missing: '
1772:         );
1773:         if (empty($lang_path)) {
1774:             // Calculate an absolute path so it can work if CWD is not here
1775:             $lang_path = dirname(__FILE__). DIRECTORY_SEPARATOR . 'language'. DIRECTORY_SEPARATOR;
1776:         }
1777:         //Validate $langcode
1778:         if (!preg_match('/^[a-z]{2}(?:_[a-zA-Z]{2})?$/', $langcode)) {
1779:             $langcode = 'en';
1780:         }
1781:         $foundlang = true;
1782:         $lang_file = $lang_path . 'phpmailer.lang-' . $langcode . '.php';
1783:         // There is no English translation file
1784:         if ($langcode != 'en') {
1785:             // Make sure language file path is readable
1786:             if (!is_readable($lang_file)) {
1787:                 $foundlang = false;
1788:             } else {
1789:                 // Overwrite language-specific strings.
1790:                 // This way we'll never have missing translation keys.
1791:                 $foundlang = include $lang_file;
1792:             }
1793:         }
1794:         $this->language = $PHPMAILER_LANG;
1795:         return (boolean)$foundlang; // Returns false if language not found
1796:     }
1797: 
1798:     /**
1799:      * Get the array of strings for the current language.
1800:      * @return array
1801:      */
1802:     public function getTranslations()
1803:     {
1804:         return $this->language;
1805:     }
1806: 
1807:     /**
1808:      * Create recipient headers.
1809:      * @access public
1810:      * @param string $type
1811:      * @param array $addr An array of recipient,
1812:      * where each recipient is a 2-element indexed array with element 0 containing an address
1813:      * and element 1 containing a name, like:
1814:      * array(array('joe@example.com', 'Joe User'), array('zoe@example.com', 'Zoe User'))
1815:      * @return string
1816:      */
1817:     public function addrAppend($type, $addr)
1818:     {
1819:         $addresses = array();
1820:         foreach ($addr as $address) {
1821:             $addresses[] = $this->addrFormat($address);
1822:         }
1823:         return $type . ': ' . implode(', ', $addresses) . $this->LE;
1824:     }
1825: 
1826:     /**
1827:      * Format an address for use in a message header.
1828:      * @access public
1829:      * @param array $addr A 2-element indexed array, element 0 containing an address, element 1 containing a name
1830:      *      like array('joe@example.com', 'Joe User')
1831:      * @return string
1832:      */
1833:     public function addrFormat($addr)
1834:     {
1835:         if (empty($addr[1])) { // No name provided
1836:             return $this->secureHeader($addr[0]);
1837:         } else {
1838:             return $this->encodeHeader($this->secureHeader($addr[1]), 'phrase') . ' <' . $this->secureHeader(
1839:                 $addr[0]
1840:             ) . '>';
1841:         }
1842:     }
1843: 
1844:     /**
1845:      * Word-wrap message.
1846:      * For use with mailers that do not automatically perform wrapping
1847:      * and for quoted-printable encoded messages.
1848:      * Original written by philippe.
1849:      * @param string $message The message to wrap
1850:      * @param integer $length The line length to wrap to
1851:      * @param boolean $qp_mode Whether to run in Quoted-Printable mode
1852:      * @access public
1853:      * @return string
1854:      */
1855:     public function wrapText($message, $length, $qp_mode = false)
1856:     {
1857:         if ($qp_mode) {
1858:             $soft_break = sprintf(' =%s', $this->LE);
1859:         } else {
1860:             $soft_break = $this->LE;
1861:         }
1862:         // If utf-8 encoding is used, we will need to make sure we don't
1863:         // split multibyte characters when we wrap
1864:         $is_utf8 = (strtolower($this->CharSet) == 'utf-8');
1865:         $lelen = strlen($this->LE);
1866:         $crlflen = strlen(self::CRLF);
1867: 
1868:         $message = $this->fixEOL($message);
1869:         //Remove a trailing line break
1870:         if (substr($message, -$lelen) == $this->LE) {
1871:             $message = substr($message, 0, -$lelen);
1872:         }
1873: 
1874:         //Split message into lines
1875:         $lines = explode($this->LE, $message);
1876:         //Message will be rebuilt in here
1877:         $message = '';
1878:         foreach ($lines as $line) {
1879:             $words = explode(' ', $line);
1880:             $buf = '';
1881:             $firstword = true;
1882:             foreach ($words as $word) {
1883:                 if ($qp_mode and (strlen($word) > $length)) {
1884:                     $space_left = $length - strlen($buf) - $crlflen;
1885:                     if (!$firstword) {
1886:                         if ($space_left > 20) {
1887:                             $len = $space_left;
1888:                             if ($is_utf8) {
1889:                                 $len = $this->utf8CharBoundary($word, $len);
1890:                             } elseif (substr($word, $len - 1, 1) == '=') {
1891:                                 $len--;
1892:                             } elseif (substr($word, $len - 2, 1) == '=') {
1893:                                 $len -= 2;
1894:                             }
1895:                             $part = substr($word, 0, $len);
1896:                             $word = substr($word, $len);
1897:                             $buf .= ' ' . $part;
1898:                             $message .= $buf . sprintf('=%s', self::CRLF);
1899:                         } else {
1900:                             $message .= $buf . $soft_break;
1901:                         }
1902:                         $buf = '';
1903:                     }
1904:                     while (strlen($word) > 0) {
1905:                         if ($length <= 0) {
1906:                             break;
1907:                         }
1908:                         $len = $length;
1909:                         if ($is_utf8) {
1910:                             $len = $this->utf8CharBoundary($word, $len);
1911:                         } elseif (substr($word, $len - 1, 1) == '=') {
1912:                             $len--;
1913:                         } elseif (substr($word, $len - 2, 1) == '=') {
1914:                             $len -= 2;
1915:                         }
1916:                         $part = substr($word, 0, $len);
1917:                         $word = substr($word, $len);
1918: 
1919:                         if (strlen($word) > 0) {
1920:                             $message .= $part . sprintf('=%s', self::CRLF);
1921:                         } else {
1922:                             $buf = $part;
1923:                         }
1924:                     }
1925:                 } else {
1926:                     $buf_o = $buf;
1927:                     if (!$firstword) {
1928:                         $buf .= ' ';
1929:                     }
1930:                     $buf .= $word;
1931: 
1932:                     if (strlen($buf) > $length and $buf_o != '') {
1933:                         $message .= $buf_o . $soft_break;
1934:                         $buf = $word;
1935:                     }
1936:                 }
1937:                 $firstword = false;
1938:             }
1939:             $message .= $buf . self::CRLF;
1940:         }
1941: 
1942:         return $message;
1943:     }
1944: 
1945:     /**
1946:      * Find the last character boundary prior to $maxLength in a utf-8
1947:      * quoted-printable encoded string.
1948:      * Original written by Colin Brown.
1949:      * @access public
1950:      * @param string $encodedText utf-8 QP text
1951:      * @param integer $maxLength Find the last character boundary prior to this length
1952:      * @return integer
1953:      */
1954:     public function utf8CharBoundary($encodedText, $maxLength)
1955:     {
1956:         $foundSplitPos = false;
1957:         $lookBack = 3;
1958:         while (!$foundSplitPos) {
1959:             $lastChunk = substr($encodedText, $maxLength - $lookBack, $lookBack);
1960:             $encodedCharPos = strpos($lastChunk, '=');
1961:             if (false !== $encodedCharPos) {
1962:                 // Found start of encoded character byte within $lookBack block.
1963:                 // Check the encoded byte value (the 2 chars after the '=')
1964:                 $hex = substr($encodedText, $maxLength - $lookBack + $encodedCharPos + 1, 2);
1965:                 $dec = hexdec($hex);
1966:                 if ($dec < 128) {
1967:                     // Single byte character.
1968:                     // If the encoded char was found at pos 0, it will fit
1969:                     // otherwise reduce maxLength to start of the encoded char
1970:                     if ($encodedCharPos > 0) {
1971:                         $maxLength = $maxLength - ($lookBack - $encodedCharPos);
1972:                     }
1973:                     $foundSplitPos = true;
1974:                 } elseif ($dec >= 192) {
1975:                     // First byte of a multi byte character
1976:                     // Reduce maxLength to split at start of character
1977:                     $maxLength = $maxLength - ($lookBack - $encodedCharPos);
1978:                     $foundSplitPos = true;
1979:                 } elseif ($dec < 192) {
1980:                     // Middle byte of a multi byte character, look further back
1981:                     $lookBack += 3;
1982:                 }
1983:             } else {
1984:                 // No encoded character found
1985:                 $foundSplitPos = true;
1986:             }
1987:         }
1988:         return $maxLength;
1989:     }
1990: 
1991:     /**
1992:      * Apply word wrapping to the message body.
1993:      * Wraps the message body to the number of chars set in the WordWrap property.
1994:      * You should only do this to plain-text bodies as wrapping HTML tags may break them.
1995:      * This is called automatically by createBody(), so you don't need to call it yourself.
1996:      * @access public
1997:      * @return void
1998:      */
1999:     public function setWordWrap()
2000:     {
2001:         if ($this->WordWrap < 1) {
2002:             return;
2003:         }
2004: 
2005:         switch ($this->message_type) {
2006:             case 'alt':
2007:             case 'alt_inline':
2008:             case 'alt_attach':
2009:             case 'alt_inline_attach':
2010:                 $this->AltBody = $this->wrapText($this->AltBody, $this->WordWrap);
2011:                 break;
2012:             default:
2013:                 $this->Body = $this->wrapText($this->Body, $this->WordWrap);
2014:                 break;
2015:         }
2016:     }
2017: 
2018:     /**
2019:      * Assemble message headers.
2020:      * @access public
2021:      * @return string The assembled headers
2022:      */
2023:     public function createHeader()
2024:     {
2025:         $result = '';
2026: 
2027:         if ($this->MessageDate == '') {
2028:             $this->MessageDate = self::rfcDate();
2029:         }
2030:         $result .= $this->headerLine('Date', $this->MessageDate);
2031: 
2032:         // To be created automatically by mail()
2033:         if ($this->SingleTo) {
2034:             if ($this->Mailer != 'mail') {
2035:                 foreach ($this->to as $toaddr) {
2036:                     $this->SingleToArray[] = $this->addrFormat($toaddr);
2037:                 }
2038:             }
2039:         } else {
2040:             if (count($this->to) > 0) {
2041:                 if ($this->Mailer != 'mail') {
2042:                     $result .= $this->addrAppend('To', $this->to);
2043:                 }
2044:             } elseif (count($this->cc) == 0) {
2045:                 $result .= $this->headerLine('To', 'undisclosed-recipients:;');
2046:             }
2047:         }
2048: 
2049:         $result .= $this->addrAppend('From', array(array(trim($this->From), $this->FromName)));
2050: 
2051:         // sendmail and mail() extract Cc from the header before sending
2052:         if (count($this->cc) > 0) {
2053:             $result .= $this->addrAppend('Cc', $this->cc);
2054:         }
2055: 
2056:         // sendmail and mail() extract Bcc from the header before sending
2057:         if ((
2058:                 $this->Mailer == 'sendmail' or $this->Mailer == 'qmail' or $this->Mailer == 'mail'
2059:             )
2060:             and count($this->bcc) > 0
2061:         ) {
2062:             $result .= $this->addrAppend('Bcc', $this->bcc);
2063:         }
2064: 
2065:         if (count($this->ReplyTo) > 0) {
2066:             $result .= $this->addrAppend('Reply-To', $this->ReplyTo);
2067:         }
2068: 
2069:         // mail() sets the subject itself
2070:         if ($this->Mailer != 'mail') {
2071:             $result .= $this->headerLine('Subject', $this->encodeHeader($this->secureHeader($this->Subject)));
2072:         }
2073: 
2074:         // Only allow a custom message ID if it conforms to RFC 5322 section 3.6.4
2075:         // https://tools.ietf.org/html/rfc5322#section-3.6.4
2076:         if ('' != $this->MessageID and preg_match('/^<.*@.*>$/', $this->MessageID)) {
2077:             $this->lastMessageID = $this->MessageID;
2078:         } else {
2079:             $this->lastMessageID = sprintf('<%s@%s>', $this->uniqueid, $this->serverHostname());
2080:         }
2081:         $result .= $this->headerLine('Message-ID', $this->lastMessageID);
2082:         if (!is_null($this->Priority)) {
2083:             $result .= $this->headerLine('X-Priority', $this->Priority);
2084:         }
2085:         if ($this->XMailer == '') {
2086:             $result .= $this->headerLine(
2087:                 'X-Mailer',
2088:                 'PHPMailer ' . $this->Version . ' (https://github.com/PHPMailer/PHPMailer)'
2089:             );
2090:         } else {
2091:             $myXmailer = trim($this->XMailer);
2092:             if ($myXmailer) {
2093:                 $result .= $this->headerLine('X-Mailer', $myXmailer);
2094:             }
2095:         }
2096: 
2097:         if ($this->ConfirmReadingTo != '') {
2098:             $result .= $this->headerLine('Disposition-Notification-To', '<' . $this->ConfirmReadingTo . '>');
2099:         }
2100: 
2101:         // Add custom headers
2102:         foreach ($this->CustomHeader as $header) {
2103:             $result .= $this->headerLine(
2104:                 trim($header[0]),
2105:                 $this->encodeHeader(trim($header[1]))
2106:             );
2107:         }
2108:         if (!$this->sign_key_file) {
2109:             $result .= $this->headerLine('MIME-Version', '1.0');
2110:             $result .= $this->getMailMIME();
2111:         }
2112: 
2113:         return $result;
2114:     }
2115: 
2116:     /**
2117:      * Get the message MIME type headers.
2118:      * @access public
2119:      * @return string
2120:      */
2121:     public function getMailMIME()
2122:     {
2123:         $result = '';
2124:         $ismultipart = true;
2125:         switch ($this->message_type) {
2126:             case 'inline':
2127:                 $result .= $this->headerLine('Content-Type', 'multipart/related;');
2128:                 $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"');
2129:                 break;
2130:             case 'attach':
2131:             case 'inline_attach':
2132:             case 'alt_attach':
2133:             case 'alt_inline_attach':
2134:                 $result .= $this->headerLine('Content-Type', 'multipart/mixed;');
2135:                 $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"');
2136:                 break;
2137:             case 'alt':
2138:             case 'alt_inline':
2139:                 $result .= $this->headerLine('Content-Type', 'multipart/alternative;');
2140:                 $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"');
2141:                 break;
2142:             default:
2143:                 // Catches case 'plain': and case '':
2144:                 $result .= $this->textLine('Content-Type: ' . $this->ContentType . '; charset=' . $this->CharSet);
2145:                 $ismultipart = false;
2146:                 break;
2147:         }
2148:         // RFC1341 part 5 says 7bit is assumed if not specified
2149:         if ($this->Encoding != '7bit') {
2150:             // RFC 2045 section 6.4 says multipart MIME parts may only use 7bit, 8bit or binary CTE
2151:             if ($ismultipart) {
2152:                 if ($this->Encoding == '8bit') {
2153:                     $result .= $this->headerLine('Content-Transfer-Encoding', '8bit');
2154:                 }
2155:                 // The only remaining alternatives are quoted-printable and base64, which are both 7bit compatible
2156:             } else {
2157:                 $result .= $this->headerLine('Content-Transfer-Encoding', $this->Encoding);
2158:             }
2159:         }
2160: 
2161:         if ($this->Mailer != 'mail') {
2162:             $result .= $this->LE;
2163:         }
2164: 
2165:         return $result;
2166:     }
2167: 
2168:     /**
2169:      * Returns the whole MIME message.
2170:      * Includes complete headers and body.
2171:      * Only valid post preSend().
2172:      * @see PHPMailer::preSend()
2173:      * @access public
2174:      * @return string
2175:      */
2176:     public function getSentMIMEMessage()
2177:     {
2178:         return rtrim($this->MIMEHeader . $this->mailHeader, "\n\r") . self::CRLF . self::CRLF . $this->MIMEBody;
2179:     }
2180: 
2181:     /**
2182:      * Create unique ID
2183:      * @return string
2184:      */
2185:     protected function generateId() {
2186:         return md5(uniqid(time()));
2187:     }
2188: 
2189:     /**
2190:      * Assemble the message body.
2191:      * Returns an empty string on failure.
2192:      * @access public
2193:      * @throws phpmailerException
2194:      * @return string The assembled message body
2195:      */
2196:     public function createBody()
2197:     {
2198:         $body = '';
2199:         //Create unique IDs and preset boundaries
2200:         $this->uniqueid = $this->generateId();
2201:         $this->boundary[1] = 'b1_' . $this->uniqueid;
2202:         $this->boundary[2] = 'b2_' . $this->uniqueid;
2203:         $this->boundary[3] = 'b3_' . $this->uniqueid;
2204: 
2205:         if ($this->sign_key_file) {
2206:             $body .= $this->getMailMIME() . $this->LE;
2207:         }
2208: 
2209:         $this->setWordWrap();
2210: 
2211:         $bodyEncoding = $this->Encoding;
2212:         $bodyCharSet = $this->CharSet;
2213:         //Can we do a 7-bit downgrade?
2214:         if ($bodyEncoding == '8bit' and !$this->has8bitChars($this->Body)) {
2215:             $bodyEncoding = '7bit';
2216:             //All ISO 8859, Windows codepage and UTF-8 charsets are ascii compatible up to 7-bit
2217:             $bodyCharSet = 'us-ascii';
2218:         }
2219:         //If lines are too long, and we're not already using an encoding that will shorten them,
2220:         //change to quoted-printable transfer encoding for the body part only
2221:         if ('base64' != $this->Encoding and self::hasLineLongerThanMax($this->Body)) {
2222:             $bodyEncoding = 'quoted-printable';
2223:         }
2224: 
2225:         $altBodyEncoding = $this->Encoding;
2226:         $altBodyCharSet = $this->CharSet;
2227:         //Can we do a 7-bit downgrade?
2228:         if ($altBodyEncoding == '8bit' and !$this->has8bitChars($this->AltBody)) {
2229:             $altBodyEncoding = '7bit';
2230:             //All ISO 8859, Windows codepage and UTF-8 charsets are ascii compatible up to 7-bit
2231:             $altBodyCharSet = 'us-ascii';
2232:         }
2233:         //If lines are too long, and we're not already using an encoding that will shorten them,
2234:         //change to quoted-printable transfer encoding for the alt body part only
2235:         if ('base64' != $altBodyEncoding and self::hasLineLongerThanMax($this->AltBody)) {
2236:             $altBodyEncoding = 'quoted-printable';
2237:         }
2238:         //Use this as a preamble in all multipart message types
2239:         $mimepre = "This is a multi-part message in MIME format." . $this->LE . $this->LE;
2240:         switch ($this->message_type) {
2241:             case 'inline':
2242:                 $body .= $mimepre;
2243:                 $body .= $this->getBoundary($this->boundary[1], $bodyCharSet, '', $bodyEncoding);
2244:                 $body .= $this->encodeString($this->Body, $bodyEncoding);
2245:                 $body .= $this->LE . $this->LE;
2246:                 $body .= $this->attachAll('inline', $this->boundary[1]);
2247:                 break;
2248:             case 'attach':
2249:                 $body .= $mimepre;
2250:                 $body .= $this->getBoundary($this->boundary[1], $bodyCharSet, '', $bodyEncoding);
2251:                 $body .= $this->encodeString($this->Body, $bodyEncoding);
2252:                 $body .= $this->LE . $this->LE;
2253:                 $body .= $this->attachAll('attachment', $this->boundary[1]);
2254:                 break;
2255:             case 'inline_attach':
2256:                 $body .= $mimepre;
2257:                 $body .= $this->textLine('--' . $this->boundary[1]);
2258:                 $body .= $this->headerLine('Content-Type', 'multipart/related;');
2259:                 $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
2260:                 $body .= $this->LE;
2261:                 $body .= $this->getBoundary($this->boundary[2], $bodyCharSet, '', $bodyEncoding);
2262:                 $body .= $this->encodeString($this->Body, $bodyEncoding);
2263:                 $body .= $this->LE . $this->LE;
2264:                 $body .= $this->attachAll('inline', $this->boundary[2]);
2265:                 $body .= $this->LE;
2266:                 $body .= $this->attachAll('attachment', $this->boundary[1]);
2267:                 break;
2268:             case 'alt':
2269:                 $body .= $mimepre;
2270:                 $body .= $this->getBoundary($this->boundary[1], $altBodyCharSet, 'text/plain', $altBodyEncoding);
2271:                 $body .= $this->encodeString($this->AltBody, $altBodyEncoding);
2272:                 $body .= $this->LE . $this->LE;
2273:                 $body .= $this->getBoundary($this->boundary[1], $bodyCharSet, 'text/html', $bodyEncoding);
2274:                 $body .= $this->encodeString($this->Body, $bodyEncoding);
2275:                 $body .= $this->LE . $this->LE;
2276:                 if (!empty($this->Ical)) {
2277:                     $body .= $this->getBoundary($this->boundary[1], '', 'text/calendar; method=REQUEST', '');
2278:                     $body .= $this->encodeString($this->Ical, $this->Encoding);
2279:                     $body .= $this->LE . $this->LE;
2280:                 }
2281:                 $body .= $this->endBoundary($this->boundary[1]);
2282:                 break;
2283:             case 'alt_inline':
2284:                 $body .= $mimepre;
2285:                 $body .= $this->getBoundary($this->boundary[1], $altBodyCharSet, 'text/plain', $altBodyEncoding);
2286:                 $body .= $this->encodeString($this->AltBody, $altBodyEncoding);
2287:                 $body .= $this->LE . $this->LE;
2288:                 $body .= $this->textLine('--' . $this->boundary[1]);
2289:                 $body .= $this->headerLine('Content-Type', 'multipart/related;');
2290:                 $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
2291:                 $body .= $this->LE;
2292:                 $body .= $this->getBoundary($this->boundary[2], $bodyCharSet, 'text/html', $bodyEncoding);
2293:                 $body .= $this->encodeString($this->Body, $bodyEncoding);
2294:                 $body .= $this->LE . $this->LE;
2295:                 $body .= $this->attachAll('inline', $this->boundary[2]);
2296:                 $body .= $this->LE;
2297:                 $body .= $this->endBoundary($this->boundary[1]);
2298:                 break;
2299:             case 'alt_attach':
2300:                 $body .= $mimepre;
2301:                 $body .= $this->textLine('--' . $this->boundary[1]);
2302:                 $body .= $this->headerLine('Content-Type', 'multipart/alternative;');
2303:                 $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
2304:                 $body .= $this->LE;
2305:                 $body .= $this->getBoundary($this->boundary[2], $altBodyCharSet, 'text/plain', $altBodyEncoding);
2306:                 $body .= $this->encodeString($this->AltBody, $altBodyEncoding);
2307:                 $body .= $this->LE . $this->LE;
2308:                 $body .= $this->getBoundary($this->boundary[2], $bodyCharSet, 'text/html', $bodyEncoding);
2309:                 $body .= $this->encodeString($this->Body, $bodyEncoding);
2310:                 $body .= $this->LE . $this->LE;
2311:                 $body .= $this->endBoundary($this->boundary[2]);
2312:                 $body .= $this->LE;
2313:                 $body .= $this->attachAll('attachment', $this->boundary[1]);
2314:                 break;
2315:             case 'alt_inline_attach':
2316:                 $body .= $mimepre;
2317:                 $body .= $this->textLine('--' . $this->boundary[1]);
2318:                 $body .= $this->headerLine('Content-Type', 'multipart/alternative;');
2319:                 $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
2320:                 $body .= $this->LE;
2321:                 $body .= $this->getBoundary($this->boundary[2], $altBodyCharSet, 'text/plain', $altBodyEncoding);
2322:                 $body .= $this->encodeString($this->AltBody, $altBodyEncoding);
2323:                 $body .= $this->LE . $this->LE;
2324:                 $body .= $this->textLine('--' . $this->boundary[2]);
2325:                 $body .= $this->headerLine('Content-Type', 'multipart/related;');
2326:                 $body .= $this->textLine("\tboundary=\"" . $this->boundary[3] . '"');
2327:                 $body .= $this->LE;
2328:                 $body .= $this->getBoundary($this->boundary[3], $bodyCharSet, 'text/html', $bodyEncoding);
2329:                 $body .= $this->encodeString($this->Body, $bodyEncoding);
2330:                 $body .= $this->LE . $this->LE;
2331:                 $body .= $this->attachAll('inline', $this->boundary[3]);
2332:                 $body .= $this->LE;
2333:                 $body .= $this->endBoundary($this->boundary[2]);
2334:                 $body .= $this->LE;
2335:                 $body .= $this->attachAll('attachment', $this->boundary[1]);
2336:                 break;
2337:             default:
2338:                 // Catch case 'plain' and case '', applies to simple `text/plain` and `text/html` body content types
2339:                 //Reset the `Encoding` property in case we changed it for line length reasons
2340:                 $this->Encoding = $bodyEncoding;
2341:                 $body .= $this->encodeString($this->Body, $this->Encoding);
2342:                 break;
2343:         }
2344: 
2345:         if ($this->isError()) {
2346:             $body = '';
2347:         } elseif ($this->sign_key_file) {
2348:             try {
2349:                 if (!defined('PKCS7_TEXT')) {
2350:                     throw new phpmailerException($this->lang('extension_missing') . 'openssl');
2351:                 }
2352:                 // @TODO would be nice to use php://temp streams here, but need to wrap for PHP < 5.1
2353:                 $file = tempnam(sys_get_temp_dir(), 'mail');
2354:                 if (false === file_put_contents($file, $body)) {
2355:                     throw new phpmailerException($this->lang('signing') . ' Could not write temp file');
2356:                 }
2357:                 $signed = tempnam(sys_get_temp_dir(), 'signed');
2358:                 //Workaround for PHP bug https://bugs.php.net/bug.php?id=69197
2359:                 if (empty($this->sign_extracerts_file)) {
2360:                     $sign = @openssl_pkcs7_sign(
2361:                         $file,
2362:                         $signed,
2363:                         'file://' . realpath($this->sign_cert_file),
2364:                         array('file://' . realpath($this->sign_key_file), $this->sign_key_pass),
2365:                         null
2366:                     );
2367:                 } else {
2368:                     $sign = @openssl_pkcs7_sign(
2369:                         $file,
2370:                         $signed,
2371:                         'file://' . realpath($this->sign_cert_file),
2372:                         array('file://' . realpath($this->sign_key_file), $this->sign_key_pass),
2373:                         null,
2374:                         PKCS7_DETACHED,
2375:                         $this->sign_extracerts_file
2376:                     );
2377:                 }
2378:                 if ($sign) {
2379:                     @unlink($file);
2380:                     $body = file_get_contents($signed);
2381:                     @unlink($signed);
2382:                     //The message returned by openssl contains both headers and body, so need to split them up
2383:                     $parts = explode("\n\n", $body, 2);
2384:                     $this->MIMEHeader .= $parts[0] . $this->LE . $this->LE;
2385:                     $body = $parts[1];
2386:                 } else {
2387:                     @unlink($file);
2388:                     @unlink($signed);
2389:                     throw new phpmailerException($this->lang('signing') . openssl_error_string());
2390:                 }
2391:             } catch (phpmailerException $exc) {
2392:                 $body = '';
2393:                 if ($this->exceptions) {
2394:                     throw $exc;
2395:                 }
2396:             }
2397:         }
2398:         return $body;
2399:     }
2400: 
2401:     /**
2402:      * Return the start of a message boundary.
2403:      * @access protected
2404:      * @param string $boundary
2405:      * @param string $charSet
2406:      * @param string $contentType
2407:      * @param string $encoding
2408:      * @return string
2409:      */
2410:     protected function getBoundary($boundary, $charSet, $contentType, $encoding)
2411:     {
2412:         $result = '';
2413:         if ($charSet == '') {
2414:             $charSet = $this->CharSet;
2415:         }
2416:         if ($contentType == '') {
2417:             $contentType = $this->ContentType;
2418:         }
2419:         if ($encoding == '') {
2420:             $encoding = $this->Encoding;
2421:         }
2422:         $result .= $this->textLine('--' . $boundary);
2423:         $result .= sprintf('Content-Type: %s; charset=%s', $contentType, $charSet);
2424:         $result .= $this->LE;
2425:         // RFC1341 part 5 says 7bit is assumed if not specified
2426:         if ($encoding != '7bit') {
2427:             $result .= $this->headerLine('Content-Transfer-Encoding', $encoding);
2428:         }
2429:         $result .= $this->LE;
2430: 
2431:         return $result;
2432:     }
2433: 
2434:     /**
2435:      * Return the end of a message boundary.
2436:      * @access protected
2437:      * @param string $boundary
2438:      * @return string
2439:      */
2440:     protected function endBoundary($boundary)
2441:     {
2442:         return $this->LE . '--' . $boundary . '--' . $this->LE;
2443:     }
2444: 
2445:     /**
2446:      * Set the message type.
2447:      * PHPMailer only supports some preset message types, not arbitrary MIME structures.
2448:      * @access protected
2449:      * @return void
2450:      */
2451:     protected function setMessageType()
2452:     {
2453:         $type = array();
2454:         if ($this->alternativeExists()) {
2455:             $type[] = 'alt';
2456:         }
2457:         if ($this->inlineImageExists()) {
2458:             $type[] = 'inline';
2459:         }
2460:         if ($this->attachmentExists()) {
2461:             $type[] = 'attach';
2462:         }
2463:         $this->message_type = implode('_', $type);
2464:         if ($this->message_type == '') {
2465:             //The 'plain' message_type refers to the message having a single body element, not that it is plain-text
2466:             $this->message_type = 'plain';
2467:         }
2468:     }
2469: 
2470:     /**
2471:      * Format a header line.
2472:      * @access public
2473:      * @param string $name
2474:      * @param string $value
2475:      * @return string
2476:      */
2477:     public function headerLine($name, $value)
2478:     {
2479:         return $name . ': ' . $value . $this->LE;
2480:     }
2481: 
2482:     /**
2483:      * Return a formatted mail line.
2484:      * @access public
2485:      * @param string $value
2486:      * @return string
2487:      */
2488:     public function textLine($value)
2489:     {
2490:         return $value . $this->LE;
2491:     }
2492: 
2493:     /**
2494:      * Add an attachment from a path on the filesystem.
2495:      * Returns false if the file could not be found or read.
2496:      * @param string $path Path to the attachment.
2497:      * @param string $name Overrides the attachment name.
2498:      * @param string $encoding File encoding (see $Encoding).
2499:      * @param string $type File extension (MIME) type.
2500:      * @param string $disposition Disposition to use
2501:      * @throws phpmailerException
2502:      * @return boolean
2503:      */
2504:     public function addAttachment($path, $name = '', $encoding = 'base64', $type = '', $disposition = 'attachment')
2505:     {
2506:         try {
2507:             if (!@is_file($path)) {
2508:                 throw new phpmailerException($this->lang('file_access') . $path, self::STOP_CONTINUE);
2509:             }
2510: 
2511:             // If a MIME type is not specified, try to work it out from the file name
2512:             if ($type == '') {
2513:                 $type = self::filenameToType($path);
2514:             }
2515: 
2516:             $filename = basename($path);
2517:             if ($name == '') {
2518:                 $name = $filename;
2519:             }
2520: 
2521:             $this->attachment[] = array(
2522:                 0 => $path,
2523:                 1 => $filename,
2524:                 2 => $name,
2525:                 3 => $encoding,
2526:                 4 => $type,
2527:                 5 => false, // isStringAttachment
2528:                 6 => $disposition,
2529:                 7 => 0
2530:             );
2531: 
2532:         } catch (phpmailerException $exc) {
2533:             $this->setError($exc->getMessage());
2534:             $this->edebug($exc->getMessage());
2535:             if ($this->exceptions) {
2536:                 throw $exc;
2537:             }
2538:             return false;
2539:         }
2540:         return true;
2541:     }
2542: 
2543:     /**
2544:      * Return the array of attachments.
2545:      * @return array
2546:      */
2547:     public function getAttachments()
2548:     {
2549:         return $this->attachment;
2550:     }
2551: 
2552:     /**
2553:      * Attach all file, string, and binary attachments to the message.
2554:      * Returns an empty string on failure.
2555:      * @access protected
2556:      * @param string $disposition_type
2557:      * @param string $boundary
2558:      * @return string
2559:      */
2560:     protected function attachAll($disposition_type, $boundary)
2561:     {
2562:         // Return text of body
2563:         $mime = array();
2564:         $cidUniq = array();
2565:         $incl = array();
2566: 
2567:         // Add all attachments
2568:         foreach ($this->attachment as $attachment) {
2569:             // Check if it is a valid disposition_filter
2570:             if ($attachment[6] == $disposition_type) {
2571:                 // Check for string attachment
2572:                 $string = '';
2573:                 $path = '';
2574:                 $bString = $attachment[5];
2575:                 if ($bString) {
2576:                     $string = $attachment[0];
2577:                 } else {
2578:                     $path = $attachment[0];
2579:                 }
2580: 
2581:                 $inclhash = md5(serialize($attachment));
2582:                 if (in_array($inclhash, $incl)) {
2583:                     continue;
2584:                 }
2585:                 $incl[] = $inclhash;
2586:                 $name = $attachment[2];
2587:                 $encoding = $attachment[3];
2588:                 $type = $attachment[4];
2589:                 $disposition = $attachment[6];
2590:                 $cid = $attachment[7];
2591:                 if ($disposition == 'inline' && array_key_exists($cid, $cidUniq)) {
2592:                     continue;
2593:                 }
2594:                 $cidUniq[$cid] = true;
2595: 
2596:                 $mime[] = sprintf('--%s%s', $boundary, $this->LE);
2597:                 //Only include a filename property if we have one
2598:                 if (!empty($name)) {
2599:                     $mime[] = sprintf(
2600:                         'Content-Type: %s; name="%s"%s',
2601:                         $type,
2602:                         $this->encodeHeader($this->secureHeader($name)),
2603:                         $this->LE
2604:                     );
2605:                 } else {
2606:                     $mime[] = sprintf(
2607:                         'Content-Type: %s%s',
2608:                         $type,
2609:                         $this->LE
2610:                     );
2611:                 }
2612:                 // RFC1341 part 5 says 7bit is assumed if not specified
2613:                 if ($encoding != '7bit') {
2614:                     $mime[] = sprintf('Content-Transfer-Encoding: %s%s', $encoding, $this->LE);
2615:                 }
2616: 
2617:                 if ($disposition == 'inline') {
2618:                     $mime[] = sprintf('Content-ID: <%s>%s', $cid, $this->LE);
2619:                 }
2620: 
2621:                 // If a filename contains any of these chars, it should be quoted,
2622:                 // but not otherwise: RFC2183 & RFC2045 5.1
2623:                 // Fixes a warning in IETF's msglint MIME checker
2624:                 // Allow for bypassing the Content-Disposition header totally
2625:                 if (!(empty($disposition))) {
2626:                     $encoded_name = $this->encodeHeader($this->secureHeader($name));
2627:                     if (preg_match('/[ \(\)<>@,;:\\"\/\[\]\?=]/', $encoded_name)) {
2628:                         $mime[] = sprintf(
2629:                             'Content-Disposition: %s; filename="%s"%s',
2630:                             $disposition,
2631:                             $encoded_name,
2632:                             $this->LE . $this->LE
2633:                         );
2634:                     } else {
2635:                         if (!empty($encoded_name)) {
2636:                             $mime[] = sprintf(
2637:                                 'Content-Disposition: %s; filename=%s%s',
2638:                                 $disposition,
2639:                                 $encoded_name,
2640:                                 $this->LE . $this->LE
2641:                             );
2642:                         } else {
2643:                             $mime[] = sprintf(
2644:                                 'Content-Disposition: %s%s',
2645:                                 $disposition,
2646:                                 $this->LE . $this->LE
2647:                             );
2648:                         }
2649:                     }
2650:                 } else {
2651:                     $mime[] = $this->LE;
2652:                 }
2653: 
2654:                 // Encode as string attachment
2655:                 if ($bString) {
2656:                     $mime[] = $this->encodeString($string, $encoding);
2657:                     if ($this->isError()) {
2658:                         return '';
2659:                     }
2660:                     $mime[] = $this->LE . $this->LE;
2661:                 } else {
2662:                     $mime[] = $this->encodeFile($path, $encoding);
2663:                     if ($this->isError()) {
2664:                         return '';
2665:                     }
2666:                     $mime[] = $this->LE . $this->LE;
2667:                 }
2668:             }
2669:         }
2670: 
2671:         $mime[] = sprintf('--%s--%s', $boundary, $this->LE);
2672: 
2673:         return implode('', $mime);
2674:     }
2675: 
2676:     /**
2677:      * Encode a file attachment in requested format.
2678:      * Returns an empty string on failure.
2679:      * @param string $path The full path to the file
2680:      * @param string $encoding The encoding to use; one of 'base64', '7bit', '8bit', 'binary', 'quoted-printable'
2681:      * @throws phpmailerException
2682:      * @access protected
2683:      * @return string
2684:      */
2685:     protected function encodeFile($path, $encoding = 'base64')
2686:     {
2687:         try {
2688:             if (!is_readable($path)) {
2689:                 throw new phpmailerException($this->lang('file_open') . $path, self::STOP_CONTINUE);
2690:             }
2691:             $magic_quotes = get_magic_quotes_runtime();
2692:             if ($magic_quotes) {
2693:                 if (version_compare(PHP_VERSION, '5.3.0', '<')) {
2694:                     set_magic_quotes_runtime(false);
2695:                 } else {
2696:                     //Doesn't exist in PHP 5.4, but we don't need to check because
2697:                     //get_magic_quotes_runtime always returns false in 5.4+
2698:                     //so it will never get here
2699:                     ini_set('magic_quotes_runtime', false);
2700:                 }
2701:             }
2702:             $file_buffer = file_get_contents($path);
2703:             $file_buffer = $this->encodeString($file_buffer, $encoding);
2704:             if ($magic_quotes) {
2705:                 if (version_compare(PHP_VERSION, '5.3.0', '<')) {
2706:                     set_magic_quotes_runtime($magic_quotes);
2707:                 } else {
2708:                     ini_set('magic_quotes_runtime', $magic_quotes);
2709:                 }
2710:             }
2711:             return $file_buffer;
2712:         } catch (Exception $exc) {
2713:             $this->setError($exc->getMessage());
2714:             return '';
2715:         }
2716:     }
2717: 
2718:     /**
2719:      * Encode a string in requested format.
2720:      * Returns an empty string on failure.
2721:      * @param string $str The text to encode
2722:      * @param string $encoding The encoding to use; one of 'base64', '7bit', '8bit', 'binary', 'quoted-printable'
2723:      * @access public
2724:      * @return string
2725:      */
2726:     public function encodeString($str, $encoding = 'base64')
2727:     {
2728:         $encoded = '';
2729:         switch (strtolower($encoding)) {
2730:             case 'base64':
2731:                 $encoded = chunk_split(base64_encode($str), 76, $this->LE);
2732:                 break;
2733:             case '7bit':
2734:             case '8bit':
2735:                 $encoded = $this->fixEOL($str);
2736:                 // Make sure it ends with a line break
2737:                 if (substr($encoded, -(strlen($this->LE))) != $this->LE) {
2738:                     $encoded .= $this->LE;
2739:                 }
2740:                 break;
2741:             case 'binary':
2742:                 $encoded = $str;
2743:                 break;
2744:             case 'quoted-printable':
2745:                 $encoded = $this->encodeQP($str);
2746:                 break;
2747:             default:
2748:                 $this->setError($this->lang('encoding') . $encoding);
2749:                 break;
2750:         }
2751:         return $encoded;
2752:     }
2753: 
2754:     /**
2755:      * Encode a header string optimally.
2756:      * Picks shortest of Q, B, quoted-printable or none.
2757:      * @access public
2758:      * @param string $str
2759:      * @param string $position
2760:      * @return string
2761:      */
2762:     public function encodeHeader($str, $position = 'text')
2763:     {
2764:         $matchcount = 0;
2765:         switch (strtolower($position)) {
2766:             case 'phrase':
2767:                 if (!preg_match('/[\200-\377]/', $str)) {
2768:                     // Can't use addslashes as we don't know the value of magic_quotes_sybase
2769:                     $encoded = addcslashes($str, "\0..\37\177\\\"");
2770:                     if (($str == $encoded) && !preg_match('/[^A-Za-z0-9!#$%&\'*+\/=?^_`{|}~ -]/', $str)) {
2771:                         return ($encoded);
2772:                     } else {
2773:                         return ("\"$encoded\"");
2774:                     }
2775:                 }
2776:                 $matchcount = preg_match_all('/[^\040\041\043-\133\135-\176]/', $str, $matches);
2777:                 break;
2778:             /** @noinspection PhpMissingBreakStatementInspection */
2779:             case 'comment':
2780:                 $matchcount = preg_match_all('/[()"]/', $str, $matches);
2781:                 // Intentional fall-through
2782:             case 'text':
2783:             default:
2784:                 $matchcount += preg_match_all('/[\000-\010\013\014\016-\037\177-\377]/', $str, $matches);
2785:                 break;
2786:         }
2787: 
2788:         //There are no chars that need encoding
2789:         if ($matchcount == 0) {
2790:             return ($str);
2791:         }
2792: 
2793:         $maxlen = 75 - 7 - strlen($this->CharSet);
2794:         // Try to select the encoding which should produce the shortest output
2795:         if ($matchcount > strlen($str) / 3) {
2796:             // More than a third of the content will need encoding, so B encoding will be most efficient
2797:             $encoding = 'B';
2798:             if (function_exists('mb_strlen') && $this->hasMultiBytes($str)) {
2799:                 // Use a custom function which correctly encodes and wraps long
2800:                 // multibyte strings without breaking lines within a character
2801:                 $encoded = $this->base64EncodeWrapMB($str, "\n");
2802:             } else {
2803:                 $encoded = base64_encode($str);
2804:                 $maxlen -= $maxlen % 4;
2805:                 $encoded = trim(chunk_split($encoded, $maxlen, "\n"));
2806:             }
2807:         } else {
2808:             $encoding = 'Q';
2809:             $encoded = $this->encodeQ($str, $position);
2810:             $encoded = $this->wrapText($encoded, $maxlen, true);
2811:             $encoded = str_replace('=' . self::CRLF, "\n", trim($encoded));
2812:         }
2813: 
2814:         $encoded = preg_replace('/^(.*)$/m', ' =?' . $this->CharSet . "?$encoding?\\1?=", $encoded);
2815:         $encoded = trim(str_replace("\n", $this->LE, $encoded));
2816: 
2817:         return $encoded;
2818:     }
2819: 
2820:     /**
2821:      * Check if a string contains multi-byte characters.
2822:      * @access public
2823:      * @param string $str multi-byte text to wrap encode
2824:      * @return boolean
2825:      */
2826:     public function hasMultiBytes($str)
2827:     {
2828:         if (function_exists('mb_strlen')) {
2829:             return (strlen($str) > mb_strlen($str, $this->CharSet));
2830:         } else { // Assume no multibytes (we can't handle without mbstring functions anyway)
2831:             return false;
2832:         }
2833:     }
2834: 
2835:     /**
2836:      * Does a string contain any 8-bit chars (in any charset)?
2837:      * @param string $text
2838:      * @return boolean
2839:      */
2840:     public function has8bitChars($text)
2841:     {
2842:         return (boolean)preg_match('/[\x80-\xFF]/', $text);
2843:     }
2844: 
2845:     /**
2846:      * Encode and wrap long multibyte strings for mail headers
2847:      * without breaking lines within a character.
2848:      * Adapted from a function by paravoid
2849:      * @link http://www.php.net/manual/en/function.mb-encode-mimeheader.php#60283
2850:      * @access public
2851:      * @param string $str multi-byte text to wrap encode
2852:      * @param string $linebreak string to use as linefeed/end-of-line
2853:      * @return string
2854:      */
2855:     public function base64EncodeWrapMB($str, $linebreak = null)
2856:     {
2857:         $start = '=?' . $this->CharSet . '?B?';
2858:         $end = '?=';
2859:         $encoded = '';
2860:         if ($linebreak === null) {
2861:             $linebreak = $this->LE;
2862:         }
2863: 
2864:         $mb_length = mb_strlen($str, $this->CharSet);
2865:         // Each line must have length <= 75, including $start and $end
2866:         $length = 75 - strlen($start) - strlen($end);
2867:         // Average multi-byte ratio
2868:         $ratio = $mb_length / strlen($str);
2869:         // Base64 has a 4:3 ratio
2870:         $avgLength = floor($length * $ratio * .75);
2871: 
2872:         for ($i = 0; $i < $mb_length; $i += $offset) {
2873:             $lookBack = 0;
2874:             do {
2875:                 $offset = $avgLength - $lookBack;
2876:                 $chunk = mb_substr($str, $i, $offset, $this->CharSet);
2877:                 $chunk = base64_encode($chunk);
2878:                 $lookBack++;
2879:             } while (strlen($chunk) > $length);
2880:             $encoded .= $chunk . $linebreak;
2881:         }
2882: 
2883:         // Chomp the last linefeed
2884:         $encoded = substr($encoded, 0, -strlen($linebreak));
2885:         return $encoded;
2886:     }
2887: 
2888:     /**
2889:      * Encode a string in quoted-printable format.
2890:      * According to RFC2045 section 6.7.
2891:      * @access public
2892:      * @param string $string The text to encode
2893:      * @param integer $line_max Number of chars allowed on a line before wrapping
2894:      * @return string
2895:      * @link http://www.php.net/manual/en/function.quoted-printable-decode.php#89417 Adapted from this comment
2896:      */
2897:     public function encodeQP($string, $line_max = 76)
2898:     {
2899:         // Use native function if it's available (>= PHP5.3)
2900:         if (function_exists('quoted_printable_encode')) {
2901:             return quoted_printable_encode($string);
2902:         }
2903:         // Fall back to a pure PHP implementation
2904:         $string = str_replace(
2905:             array('%20', '%0D%0A.', '%0D%0A', '%'),
2906:             array(' ', "\r\n=2E", "\r\n", '='),
2907:             rawurlencode($string)
2908:         );
2909:         return preg_replace('/[^\r\n]{' . ($line_max - 3) . '}[^=\r\n]{2}/', "$0=\r\n", $string);
2910:     }
2911: 
2912:     /**
2913:      * Backward compatibility wrapper for an old QP encoding function that was removed.
2914:      * @see PHPMailer::encodeQP()
2915:      * @access public
2916:      * @param string $string
2917:      * @param integer $line_max
2918:      * @param boolean $space_conv
2919:      * @return string
2920:      * @deprecated Use encodeQP instead.
2921:      */
2922:     public function encodeQPphp(
2923:         $string,
2924:         $line_max = 76,
2925:         /** @noinspection PhpUnusedParameterInspection */ $space_conv = false
2926:     ) {
2927:         return $this->encodeQP($string, $line_max);
2928:     }
2929: 
2930:     /**
2931:      * Encode a string using Q encoding.
2932:      * @link http://tools.ietf.org/html/rfc2047
2933:      * @param string $str the text to encode
2934:      * @param string $position Where the text is going to be used, see the RFC for what that means
2935:      * @access public
2936:      * @return string
2937:      */
2938:     public function encodeQ($str, $position = 'text')
2939:     {
2940:         // There should not be any EOL in the string
2941:         $pattern = '';
2942:         $encoded = str_replace(array("\r", "\n"), '', $str);
2943:         switch (strtolower($position)) {
2944:             case 'phrase':
2945:                 // RFC 2047 section 5.3
2946:                 $pattern = '^A-Za-z0-9!*+\/ -';
2947:                 break;
2948:             /** @noinspection PhpMissingBreakStatementInspection */
2949:             case 'comment':
2950:                 // RFC 2047 section 5.2
2951:                 $pattern = '\(\)"';
2952:                 // intentional fall-through
2953:                 // for this reason we build the $pattern without including delimiters and []
2954:             case 'text':
2955:             default:
2956:                 // RFC 2047 section 5.1
2957:                 // Replace every high ascii, control, =, ? and _ characters
2958:                 $pattern = '\000-\011\013\014\016-\037\075\077\137\177-\377' . $pattern;
2959:                 break;
2960:         }
2961:         $matches = array();
2962:         if (preg_match_all("/[{$pattern}]/", $encoded, $matches)) {
2963:             // If the string contains an '=', make sure it's the first thing we replace
2964:             // so as to avoid double-encoding
2965:             $eqkey = array_search('=', $matches[0]);
2966:             if (false !== $eqkey) {
2967:                 unset($matches[0][$eqkey]);
2968:                 array_unshift($matches[0], '=');
2969:             }
2970:             foreach (array_unique($matches[0]) as $char) {
2971:                 $encoded = str_replace($char, '=' . sprintf('%02X', ord($char)), $encoded);
2972:             }
2973:         }
2974:         // Replace every spaces to _ (more readable than =20)
2975:         return str_replace(' ', '_', $encoded);
2976:     }
2977: 
2978:     /**
2979:      * Add a string or binary attachment (non-filesystem).
2980:      * This method can be used to attach ascii or binary data,
2981:      * such as a BLOB record from a database.
2982:      * @param string $string String attachment data.
2983:      * @param string $filename Name of the attachment.
2984:      * @param string $encoding File encoding (see $Encoding).
2985:      * @param string $type File extension (MIME) type.
2986:      * @param string $disposition Disposition to use
2987:      * @return void
2988:      */
2989:     public function addStringAttachment(
2990:         $string,
2991:         $filename,
2992:         $encoding = 'base64',
2993:         $type = '',
2994:         $disposition = 'attachment'
2995:     ) {
2996:         // If a MIME type is not specified, try to work it out from the file name
2997:         if ($type == '') {
2998:             $type = self::filenameToType($filename);
2999:         }
3000:         // Append to $attachment array
3001:         $this->attachment[] = array(
3002:             0 => $string,
3003:             1 => $filename,
3004:             2 => basename($filename),
3005:             3 => $encoding,
3006:             4 => $type,
3007:             5 => true, // isStringAttachment
3008:             6 => $disposition,
3009:             7 => 0
3010:         );
3011:     }
3012: 
3013:     /**
3014:      * Add an embedded (inline) attachment from a file.
3015:      * This can include images, sounds, and just about any other document type.
3016:      * These differ from 'regular' attachments in that they are intended to be
3017:      * displayed inline with the message, not just attached for download.
3018:      * This is used in HTML messages that embed the images
3019:      * the HTML refers to using the $cid value.
3020:      * @param string $path Path to the attachment.
3021:      * @param string $cid Content ID of the attachment; Use this to reference
3022:      *        the content when using an embedded image in HTML.
3023:      * @param string $name Overrides the attachment name.
3024:      * @param string $encoding File encoding (see $Encoding).
3025:      * @param string $type File MIME type.
3026:      * @param string $disposition Disposition to use
3027:      * @return boolean True on successfully adding an attachment
3028:      */
3029:     public function addEmbeddedImage($path, $cid, $name = '', $encoding = 'base64', $type = '', $disposition = 'inline')
3030:     {
3031:         if (!@is_file($path)) {
3032:             $this->setError($this->lang('file_access') . $path);
3033:             return false;
3034:         }
3035: 
3036:         // If a MIME type is not specified, try to work it out from the file name
3037:         if ($type == '') {
3038:             $type = self::filenameToType($path);
3039:         }
3040: 
3041:         $filename = basename($path);
3042:         if ($name == '') {
3043:             $name = $filename;
3044:         }
3045: 
3046:         // Append to $attachment array
3047:         $this->attachment[] = array(
3048:             0 => $path,
3049:             1 => $filename,
3050:             2 => $name,
3051:             3 => $encoding,
3052:             4 => $type,
3053:             5 => false, // isStringAttachment
3054:             6 => $disposition,
3055:             7 => $cid
3056:         );
3057:         return true;
3058:     }
3059: 
3060:     /**
3061:      * Add an embedded stringified attachment.
3062:      * This can include images, sounds, and just about any other document type.
3063:      * Be sure to set the $type to an image type for images:
3064:      * JPEG images use 'image/jpeg', GIF uses 'image/gif', PNG uses 'image/png'.
3065:      * @param string $string The attachment binary data.
3066:      * @param string $cid Content ID of the attachment; Use this to reference
3067:      *        the content when using an embedded image in HTML.
3068:      * @param string $name
3069:      * @param string $encoding File encoding (see $Encoding).
3070:      * @param string $type MIME type.
3071:      * @param string $disposition Disposition to use
3072:      * @return boolean True on successfully adding an attachment
3073:      */
3074:     public function addStringEmbeddedImage(
3075:         $string,
3076:         $cid,
3077:         $name = '',
3078:         $encoding = 'base64',
3079:         $type = '',
3080:         $disposition = 'inline'
3081:     ) {
3082:         // If a MIME type is not specified, try to work it out from the name
3083:         if ($type == '' and !empty($name)) {
3084:             $type = self::filenameToType($name);
3085:         }
3086: 
3087:         // Append to $attachment array
3088:         $this->attachment[] = array(
3089:             0 => $string,
3090:             1 => $name,
3091:             2 => $name,
3092:             3 => $encoding,
3093:             4 => $type,
3094:             5 => true, // isStringAttachment
3095:             6 => $disposition,
3096:             7 => $cid
3097:         );
3098:         return true;
3099:     }
3100: 
3101:     /**
3102:      * Check if an inline attachment is present.
3103:      * @access public
3104:      * @return boolean
3105:      */
3106:     public function inlineImageExists()
3107:     {
3108:         foreach ($this->attachment as $attachment) {
3109:             if ($attachment[6] == 'inline') {
3110:                 return true;
3111:             }
3112:         }
3113:         return false;
3114:     }
3115: 
3116:     /**
3117:      * Check if an attachment (non-inline) is present.
3118:      * @return boolean
3119:      */
3120:     public function attachmentExists()
3121:     {
3122:         foreach ($this->attachment as $attachment) {
3123:             if ($attachment[6] == 'attachment') {
3124:                 return true;
3125:             }
3126:         }
3127:         return false;
3128:     }
3129: 
3130:     /**
3131:      * Check if this message has an alternative body set.
3132:      * @return boolean
3133:      */
3134:     public function alternativeExists()
3135:     {
3136:         return !empty($this->AltBody);
3137:     }
3138: 
3139:     /**
3140:      * Clear queued addresses of given kind.
3141:      * @access protected
3142:      * @param string $kind 'to', 'cc', or 'bcc'
3143:      * @return void
3144:      */
3145:     public function clearQueuedAddresses($kind)
3146:     {
3147:         $RecipientsQueue = $this->RecipientsQueue;
3148:         foreach ($RecipientsQueue as $address => $params) {
3149:             if ($params[0] == $kind) {
3150:                 unset($this->RecipientsQueue[$address]);
3151:             }
3152:         }
3153:     }
3154: 
3155:     /**
3156:      * Clear all To recipients.
3157:      * @return void
3158:      */
3159:     public function clearAddresses()
3160:     {
3161:         foreach ($this->to as $to) {
3162:             unset($this->all_recipients[strtolower($to[0])]);
3163:         }
3164:         $this->to = array();
3165:         $this->clearQueuedAddresses('to');
3166:     }
3167: 
3168:     /**
3169:      * Clear all CC recipients.
3170:      * @return void
3171:      */
3172:     public function clearCCs()
3173:     {
3174:         foreach ($this->cc as $cc) {
3175:             unset($this->all_recipients[strtolower($cc[0])]);
3176:         }
3177:         $this->cc = array();
3178:         $this->clearQueuedAddresses('cc');
3179:     }
3180: 
3181:     /**
3182:      * Clear all BCC recipients.
3183:      * @return void
3184:      */
3185:     public function clearBCCs()
3186:     {
3187:         foreach ($this->bcc as $bcc) {
3188:             unset($this->all_recipients[strtolower($bcc[0])]);
3189:         }
3190:         $this->bcc = array();
3191:         $this->clearQueuedAddresses('bcc');
3192:     }
3193: 
3194:     /**
3195:      * Clear all ReplyTo recipients.
3196:      * @return void
3197:      */
3198:     public function clearReplyTos()
3199:     {
3200:         $this->ReplyTo = array();
3201:         $this->ReplyToQueue = array();
3202:     }
3203: 
3204:     /**
3205:      * Clear all recipient types.
3206:      * @return void
3207:      */
3208:     public function clearAllRecipients()
3209:     {
3210:         $this->to = array();
3211:         $this->cc = array();
3212:         $this->bcc = array();
3213:         $this->all_recipients = array();
3214:         $this->RecipientsQueue = array();
3215:     }
3216: 
3217:     /**
3218:      * Clear all filesystem, string, and binary attachments.
3219:      * @return void
3220:      */
3221:     public function clearAttachments()
3222:     {
3223:         $this->attachment = array();
3224:     }
3225: 
3226:     /**
3227:      * Clear all custom headers.
3228:      * @return void
3229:      */
3230:     public function clearCustomHeaders()
3231:     {
3232:         $this->CustomHeader = array();
3233:     }
3234: 
3235:     /**
3236:      * Add an error message to the error container.
3237:      * @access protected
3238:      * @param string $msg
3239:      * @return void
3240:      */
3241:     protected function setError($msg)
3242:     {
3243:         $this->error_count++;
3244:         if ($this->Mailer == 'smtp' and !is_null($this->smtp)) {
3245:             $lasterror = $this->smtp->getError();
3246:             if (!empty($lasterror['error'])) {
3247:                 $msg .= $this->lang('smtp_error') . $lasterror['error'];
3248:                 if (!empty($lasterror['detail'])) {
3249:                     $msg .= ' Detail: '. $lasterror['detail'];
3250:                 }
3251:                 if (!empty($lasterror['smtp_code'])) {
3252:                     $msg .= ' SMTP code: ' . $lasterror['smtp_code'];
3253:                 }
3254:                 if (!empty($lasterror['smtp_code_ex'])) {
3255:                     $msg .= ' Additional SMTP info: ' . $lasterror['smtp_code_ex'];
3256:                 }
3257:             }
3258:         }
3259:         $this->ErrorInfo = $msg;
3260:     }
3261: 
3262:     /**
3263:      * Return an RFC 822 formatted date.
3264:      * @access public
3265:      * @return string
3266:      * @static
3267:      */
3268:     public static function rfcDate()
3269:     {
3270:         // Set the time zone to whatever the default is to avoid 500 errors
3271:         // Will default to UTC if it's not set properly in php.ini
3272:         date_default_timezone_set(@date_default_timezone_get());
3273:         return date('D, j M Y H:i:s O');
3274:     }
3275: 
3276:     /**
3277:      * Get the server hostname.
3278:      * Returns 'localhost.localdomain' if unknown.
3279:      * @access protected
3280:      * @return string
3281:      */
3282:     protected function serverHostname()
3283:     {
3284:         $result = 'localhost.localdomain';
3285:         if (!empty($this->Hostname)) {
3286:             $result = $this->Hostname;
3287:         } elseif (isset($_SERVER) and array_key_exists('SERVER_NAME', $_SERVER) and !empty($_SERVER['SERVER_NAME'])) {
3288:             $result = $_SERVER['SERVER_NAME'];
3289:         } elseif (function_exists('gethostname') && gethostname() !== false) {
3290:             $result = gethostname();
3291:         } elseif (php_uname('n') !== false) {
3292:             $result = php_uname('n');
3293:         }
3294:         return $result;
3295:     }
3296: 
3297:     /**
3298:      * Get an error message in the current language.
3299:      * @access protected
3300:      * @param string $key
3301:      * @return string
3302:      */
3303:     protected function lang($key)
3304:     {
3305:         if (count($this->language) < 1) {
3306:             $this->setLanguage('en'); // set the default language
3307:         }
3308: 
3309:         if (array_key_exists($key, $this->language)) {
3310:             if ($key == 'smtp_connect_failed') {
3311:                 //Include a link to troubleshooting docs on SMTP connection failure
3312:                 //this is by far the biggest cause of support questions
3313:                 //but it's usually not PHPMailer's fault.
3314:                 return $this->language[$key] . ' https://github.com/PHPMailer/PHPMailer/wiki/Troubleshooting';
3315:             }
3316:             return $this->language[$key];
3317:         } else {
3318:             //Return the key as a fallback
3319:             return $key;
3320:         }
3321:     }
3322: 
3323:     /**
3324:      * Check if an error occurred.
3325:      * @access public
3326:      * @return boolean True if an error did occur.
3327:      */
3328:     public function isError()
3329:     {
3330:         return ($this->error_count > 0);
3331:     }
3332: 
3333:     /**
3334:      * Ensure consistent line endings in a string.
3335:      * Changes every end of line from CRLF, CR or LF to $this->LE.
3336:      * @access public
3337:      * @param string $str String to fixEOL
3338:      * @return string
3339:      */
3340:     public function fixEOL($str)
3341:     {
3342:         // Normalise to \n
3343:         $nstr = str_replace(array("\r\n", "\r"), "\n", $str);
3344:         // Now convert LE as needed
3345:         if ($this->LE !== "\n") {
3346:             $nstr = str_replace("\n", $this->LE, $nstr);
3347:         }
3348:         return $nstr;
3349:     }
3350: 
3351:     /**
3352:      * Add a custom header.
3353:      * $name value can be overloaded to contain
3354:      * both header name and value (name:value)
3355:      * @access public
3356:      * @param string $name Custom header name
3357:      * @param string $value Header value
3358:      * @return void
3359:      */
3360:     public function addCustomHeader($name, $value = null)
3361:     {
3362:         if ($value === null) {
3363:             // Value passed in as name:value
3364:             $this->CustomHeader[] = explode(':', $name, 2);
3365:         } else {
3366:             $this->CustomHeader[] = array($name, $value);
3367:         }
3368:     }
3369: 
3370:     /**
3371:      * Returns all custom headers.
3372:      * @return array
3373:      */
3374:     public function getCustomHeaders()
3375:     {
3376:         return $this->CustomHeader;
3377:     }
3378: 
3379:     /**
3380:      * Create a message body from an HTML string.
3381:      * Automatically inlines images and creates a plain-text version by converting the HTML,
3382:      * overwriting any existing values in Body and AltBody.
3383:      * $basedir is used when handling relative image paths, e.g. <img src="images/a.png">
3384:      * will look for an image file in $basedir/images/a.png and convert it to inline.
3385:      * If you don't want to apply these transformations to your HTML, just set Body and AltBody yourself.
3386:      * @access public
3387:      * @param string $message HTML message string
3388:      * @param string $basedir base directory for relative paths to images
3389:      * @param boolean|callable $advanced Whether to use the internal HTML to text converter
3390:      *    or your own custom converter @see PHPMailer::html2text()
3391:      * @return string $message The transformed message Body
3392:      */
3393:     public function msgHTML($message, $basedir = '', $advanced = false)
3394:     {
3395:         preg_match_all('/(src|background)=["\'](.*)["\']/Ui', $message, $images);
3396:         if (array_key_exists(2, $images)) {
3397:             foreach ($images[2] as $imgindex => $url) {
3398:                 // Convert data URIs into embedded images
3399:                 if (preg_match('#^data:(image[^;,]*)(;base64)?,#', $url, $match)) {
3400:                     $data = substr($url, strpos($url, ','));
3401:                     if ($match[2]) {
3402:                         $data = base64_decode($data);
3403:                     } else {
3404:                         $data = rawurldecode($data);
3405:                     }
3406:                     $cid = md5($url) . '@phpmailer.0'; // RFC2392 S 2
3407:                     if ($this->addStringEmbeddedImage($data, $cid, 'embed' . $imgindex, 'base64', $match[1])) {
3408:                         $message = str_replace(
3409:                             $images[0][$imgindex],
3410:                             $images[1][$imgindex] . '="cid:' . $cid . '"',
3411:                             $message
3412:                         );
3413:                     }
3414:                 } elseif (substr($url, 0, 4) !== 'cid:' && !preg_match('#^[a-z][a-z0-9+.-]*://#i', $url)) {
3415:                     // Do not change urls for absolute images (thanks to corvuscorax)
3416:                     // Do not change urls that are already inline images
3417:                     $filename = basename($url);
3418:                     $directory = dirname($url);
3419:                     if ($directory == '.') {
3420:                         $directory = '';
3421:                     }
3422:                     $cid = md5($url) . '@phpmailer.0'; // RFC2392 S 2
3423:                     if (strlen($basedir) > 1 && substr($basedir, -1) != '/') {
3424:                         $basedir .= '/';
3425:                     }
3426:                     if (strlen($directory) > 1 && substr($directory, -1) != '/') {
3427:                         $directory .= '/';
3428:                     }
3429:                     if ($this->addEmbeddedImage(
3430:                         $basedir . $directory . $filename,
3431:                         $cid,
3432:                         $filename,
3433:                         'base64',
3434:                         self::_mime_types((string)self::mb_pathinfo($filename, PATHINFO_EXTENSION))
3435:                     )
3436:                     ) {
3437:                         $message = preg_replace(
3438:                             '/' . $images[1][$imgindex] . '=["\']' . preg_quote($url, '/') . '["\']/Ui',
3439:                             $images[1][$imgindex] . '="cid:' . $cid . '"',
3440:                             $message
3441:                         );
3442:                     }
3443:                 }
3444:             }
3445:         }
3446:         $this->isHTML(true);
3447:         // Convert all message body line breaks to CRLF, makes quoted-printable encoding work much better
3448:         $this->Body = $this->normalizeBreaks($message);
3449:         $this->AltBody = $this->normalizeBreaks($this->html2text($message, $advanced));
3450:         if (!$this->alternativeExists()) {
3451:             $this->AltBody = 'To view this email message, open it in a program that understands HTML!' .
3452:                 self::CRLF . self::CRLF;
3453:         }
3454:         return $this->Body;
3455:     }
3456: 
3457:     /**
3458:      * Convert an HTML string into plain text.
3459:      * This is used by msgHTML().
3460:      * Note - older versions of this function used a bundled advanced converter
3461:      * which was been removed for license reasons in #232.
3462:      * Example usage:
3463:      * <code>
3464:      * // Use default conversion
3465:      * $plain = $mail->html2text($html);
3466:      * // Use your own custom converter
3467:      * $plain = $mail->html2text($html, function($html) {
3468:      *     $converter = new MyHtml2text($html);
3469:      *     return $converter->get_text();
3470:      * });
3471:      * </code>
3472:      * @param string $html The HTML text to convert
3473:      * @param boolean|callable $advanced Any boolean value to use the internal converter,
3474:      *   or provide your own callable for custom conversion.
3475:      * @return string
3476:      */
3477:     public function html2text($html, $advanced = false)
3478:     {
3479:         if (is_callable($advanced)) {
3480:             return call_user_func($advanced, $html);
3481:         }
3482:         return html_entity_decode(
3483:             trim(strip_tags(preg_replace('/<(head|title|style|script)[^>]*>.*?<\/\\1>/si', '', $html))),
3484:             ENT_QUOTES,
3485:             $this->CharSet
3486:         );
3487:     }
3488: 
3489:     /**
3490:      * Get the MIME type for a file extension.
3491:      * @param string $ext File extension
3492:      * @access public
3493:      * @return string MIME type of file.
3494:      * @static
3495:      */
3496:     public static function _mime_types($ext = '')
3497:     {
3498:         $mimes = array(
3499:             'xl'    => 'application/excel',
3500:             'js'    => 'application/javascript',
3501:             'hqx'   => 'application/mac-binhex40',
3502:             'cpt'   => 'application/mac-compactpro',
3503:             'bin'   => 'application/macbinary',
3504:             'doc'   => 'application/msword',
3505:             'word'  => 'application/msword',
3506:             'xlsx'  => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
3507:             'xltx'  => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
3508:             'potx'  => 'application/vnd.openxmlformats-officedocument.presentationml.template',
3509:             'ppsx'  => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
3510:             'pptx'  => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
3511:             'sldx'  => 'application/vnd.openxmlformats-officedocument.presentationml.slide',
3512:             'docx'  => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
3513:             'dotx'  => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
3514:             'xlam'  => 'application/vnd.ms-excel.addin.macroEnabled.12',
3515:             'xlsb'  => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12',
3516:             'class' => 'application/octet-stream',
3517:             'dll'   => 'application/octet-stream',
3518:             'dms'   => 'application/octet-stream',
3519:             'exe'   => 'application/octet-stream',
3520:             'lha'   => 'application/octet-stream',
3521:             'lzh'   => 'application/octet-stream',
3522:             'psd'   => 'application/octet-stream',
3523:             'sea'   => 'application/octet-stream',
3524:             'so'    => 'application/octet-stream',
3525:             'oda'   => 'application/oda',
3526:             'pdf'   => 'application/pdf',
3527:             'ai'    => 'application/postscript',
3528:             'eps'   => 'application/postscript',
3529:             'ps'    => 'application/postscript',
3530:             'smi'   => 'application/smil',
3531:             'smil'  => 'application/smil',
3532:             'mif'   => 'application/vnd.mif',
3533:             'xls'   => 'application/vnd.ms-excel',
3534:             'ppt'   => 'application/vnd.ms-powerpoint',
3535:             'wbxml' => 'application/vnd.wap.wbxml',
3536:             'wmlc'  => 'application/vnd.wap.wmlc',
3537:             'dcr'   => 'application/x-director',
3538:             'dir'   => 'application/x-director',
3539:             'dxr'   => 'application/x-director',
3540:             'dvi'   => 'application/x-dvi',
3541:             'gtar'  => 'application/x-gtar',
3542:             'php3'  => 'application/x-httpd-php',
3543:             'php4'  => 'application/x-httpd-php',
3544:             'php'   => 'application/x-httpd-php',
3545:             'phtml' => 'application/x-httpd-php',
3546:             'phps'  => 'application/x-httpd-php-source',
3547:             'swf'   => 'application/x-shockwave-flash',
3548:             'sit'   => 'application/x-stuffit',
3549:             'tar'   => 'application/x-tar',
3550:             'tgz'   => 'application/x-tar',
3551:             'xht'   => 'application/xhtml+xml',
3552:             'xhtml' => 'application/xhtml+xml',
3553:             'zip'   => 'application/zip',
3554:             'mid'   => 'audio/midi',
3555:             'midi'  => 'audio/midi',
3556:             'mp2'   => 'audio/mpeg',
3557:             'mp3'   => 'audio/mpeg',
3558:             'mpga'  => 'audio/mpeg',
3559:             'aif'   => 'audio/x-aiff',
3560:             'aifc'  => 'audio/x-aiff',
3561:             'aiff'  => 'audio/x-aiff',
3562:             'ram'   => 'audio/x-pn-realaudio',
3563:             'rm'    => 'audio/x-pn-realaudio',
3564:             'rpm'   => 'audio/x-pn-realaudio-plugin',
3565:             'ra'    => 'audio/x-realaudio',
3566:             'wav'   => 'audio/x-wav',
3567:             'bmp'   => 'image/bmp',
3568:             'gif'   => 'image/gif',
3569:             'jpeg'  => 'image/jpeg',
3570:             'jpe'   => 'image/jpeg',
3571:             'jpg'   => 'image/jpeg',
3572:             'png'   => 'image/png',
3573:             'tiff'  => 'image/tiff',
3574:             'tif'   => 'image/tiff',
3575:             'eml'   => 'message/rfc822',
3576:             'css'   => 'text/css',
3577:             'html'  => 'text/html',
3578:             'htm'   => 'text/html',
3579:             'shtml' => 'text/html',
3580:             'log'   => 'text/plain',
3581:             'text'  => 'text/plain',
3582:             'txt'   => 'text/plain',
3583:             'rtx'   => 'text/richtext',
3584:             'rtf'   => 'text/rtf',
3585:             'vcf'   => 'text/vcard',
3586:             'vcard' => 'text/vcard',
3587:             'xml'   => 'text/xml',
3588:             'xsl'   => 'text/xml',
3589:             'mpeg'  => 'video/mpeg',
3590:             'mpe'   => 'video/mpeg',
3591:             'mpg'   => 'video/mpeg',
3592:             'mov'   => 'video/quicktime',
3593:             'qt'    => 'video/quicktime',
3594:             'rv'    => 'video/vnd.rn-realvideo',
3595:             'avi'   => 'video/x-msvideo',
3596:             'movie' => 'video/x-sgi-movie'
3597:         );
3598:         if (array_key_exists(strtolower($ext), $mimes)) {
3599:             return $mimes[strtolower($ext)];
3600:         }
3601:         return 'application/octet-stream';
3602:     }
3603: 
3604:     /**
3605:      * Map a file name to a MIME type.
3606:      * Defaults to 'application/octet-stream', i.e.. arbitrary binary data.
3607:      * @param string $filename A file name or full path, does not need to exist as a file
3608:      * @return string
3609:      * @static
3610:      */
3611:     public static function filenameToType($filename)
3612:     {
3613:         // In case the path is a URL, strip any query string before getting extension
3614:         $qpos = strpos($filename, '?');
3615:         if (false !== $qpos) {
3616:             $filename = substr($filename, 0, $qpos);
3617:         }
3618:         $pathinfo = self::mb_pathinfo($filename);
3619:         return self::_mime_types($pathinfo['extension']);
3620:     }
3621: 
3622:     /**
3623:      * Multi-byte-safe pathinfo replacement.
3624:      * Drop-in replacement for pathinfo(), but multibyte-safe, cross-platform-safe, old-version-safe.
3625:      * Works similarly to the one in PHP >= 5.2.0
3626:      * @link http://www.php.net/manual/en/function.pathinfo.php#107461
3627:      * @param string $path A filename or path, does not need to exist as a file
3628:      * @param integer|string $options Either a PATHINFO_* constant,
3629:      *      or a string name to return only the specified piece, allows 'filename' to work on PHP < 5.2
3630:      * @return string|array
3631:      * @static
3632:      */
3633:     public static function mb_pathinfo($path, $options = null)
3634:     {
3635:         $ret = array('dirname' => '', 'basename' => '', 'extension' => '', 'filename' => '');
3636:         $pathinfo = array();
3637:         if (preg_match('%^(.*?)[\\\\/]*(([^/\\\\]*?)(\.([^\.\\\\/]+?)|))[\\\\/\.]*$%im', $path, $pathinfo)) {
3638:             if (array_key_exists(1, $pathinfo)) {
3639:                 $ret['dirname'] = $pathinfo[1];
3640:             }
3641:             if (array_key_exists(2, $pathinfo)) {
3642:                 $ret['basename'] = $pathinfo[2];
3643:             }
3644:             if (array_key_exists(5, $pathinfo)) {
3645:                 $ret['extension'] = $pathinfo[5];
3646:             }
3647:             if (array_key_exists(3, $pathinfo)) {
3648:                 $ret['filename'] = $pathinfo[3];
3649:             }
3650:         }
3651:         switch ($options) {
3652:             case PATHINFO_DIRNAME:
3653:             case 'dirname':
3654:                 return $ret['dirname'];
3655:             case PATHINFO_BASENAME:
3656:             case 'basename':
3657:                 return $ret['basename'];
3658:             case PATHINFO_EXTENSION:
3659:             case 'extension':
3660:                 return $ret['extension'];
3661:             case PATHINFO_FILENAME:
3662:             case 'filename':
3663:                 return $ret['filename'];
3664:             default:
3665:                 return $ret;
3666:         }
3667:     }
3668: 
3669:     /**
3670:      * Set or reset instance properties.
3671:      * You should avoid this function - it's more verbose, less efficient, more error-prone and
3672:      * harder to debug than setting properties directly.
3673:      * Usage Example:
3674:      * `$mail->set('SMTPSecure', 'tls');`
3675:      *   is the same as:
3676:      * `$mail->SMTPSecure = 'tls';`
3677:      * @access public
3678:      * @param string $name The property name to set
3679:      * @param mixed $value The value to set the property to
3680:      * @return boolean
3681:      * @TODO Should this not be using the __set() magic function?
3682:      */
3683:     public function set($name, $value = '')
3684:     {
3685:         if (property_exists($this, $name)) {
3686:             $this->$name = $value;
3687:             return true;
3688:         } else {
3689:             $this->setError($this->lang('variable_set') . $name);
3690:             return false;
3691:         }
3692:     }
3693: 
3694:     /**
3695:      * Strip newlines to prevent header injection.
3696:      * @access public
3697:      * @param string $str
3698:      * @return string
3699:      */
3700:     public function secureHeader($str)
3701:     {
3702:         return trim(str_replace(array("\r", "\n"), '', $str));
3703:     }
3704: 
3705:     /**
3706:      * Normalize line breaks in a string.
3707:      * Converts UNIX LF, Mac CR and Windows CRLF line breaks into a single line break format.
3708:      * Defaults to CRLF (for message bodies) and preserves consecutive breaks.
3709:      * @param string $text
3710:      * @param string $breaktype What kind of line break to use, defaults to CRLF
3711:      * @return string
3712:      * @access public
3713:      * @static
3714:      */
3715:     public static function normalizeBreaks($text, $breaktype = "\r\n")
3716:     {
3717:         return preg_replace('/(\r\n|\r|\n)/ms', $breaktype, $text);
3718:     }
3719: 
3720:     /**
3721:      * Set the public and private key files and password for S/MIME signing.
3722:      * @access public
3723:      * @param string $cert_filename
3724:      * @param string $key_filename
3725:      * @param string $key_pass Password for private key
3726:      * @param string $extracerts_filename Optional path to chain certificate
3727:      */
3728:     public function sign($cert_filename, $key_filename, $key_pass, $extracerts_filename = '')
3729:     {
3730:         $this->sign_cert_file = $cert_filename;
3731:         $this->sign_key_file = $key_filename;
3732:         $this->sign_key_pass = $key_pass;
3733:         $this->sign_extracerts_file = $extracerts_filename;
3734:     }
3735: 
3736:     /**
3737:      * Quoted-Printable-encode a DKIM header.
3738:      * @access public
3739:      * @param string $txt
3740:      * @return string
3741:      */
3742:     public function DKIM_QP($txt)
3743:     {
3744:         $line = '';
3745:         for ($i = 0; $i < strlen($txt); $i++) {
3746:             $ord = ord($txt[$i]);
3747:             if (((0x21 <= $ord) && ($ord <= 0x3A)) || $ord == 0x3C || ((0x3E <= $ord) && ($ord <= 0x7E))) {
3748:                 $line .= $txt[$i];
3749:             } else {
3750:                 $line .= '=' . sprintf('%02X', $ord);
3751:             }
3752:         }
3753:         return $line;
3754:     }
3755: 
3756:     /**
3757:      * Generate a DKIM signature.
3758:      * @access public
3759:      * @param string $signHeader
3760:      * @throws phpmailerException
3761:      * @return string The DKIM signature value
3762:      */
3763:     public function DKIM_Sign($signHeader)
3764:     {
3765:         if (!defined('PKCS7_TEXT')) {
3766:             if ($this->exceptions) {
3767:                 throw new phpmailerException($this->lang('extension_missing') . 'openssl');
3768:             }
3769:             return '';
3770:         }
3771:         $privKeyStr = !empty($this->DKIM_private_string) ? $this->DKIM_private_string : file_get_contents($this->DKIM_private);
3772:         if ('' != $this->DKIM_passphrase) {
3773:             $privKey = openssl_pkey_get_private($privKeyStr, $this->DKIM_passphrase);
3774:         } else {
3775:             $privKey = openssl_pkey_get_private($privKeyStr);
3776:         }
3777:         //Workaround for missing digest algorithms in old PHP & OpenSSL versions
3778:         //@link http://stackoverflow.com/a/11117338/333340
3779:         if (version_compare(PHP_VERSION, '5.3.0') >= 0 and
3780:             in_array('sha256WithRSAEncryption', openssl_get_md_methods(true))) {
3781:             if (openssl_sign($signHeader, $signature, $privKey, 'sha256WithRSAEncryption')) {
3782:                 openssl_pkey_free($privKey);
3783:                 return base64_encode($signature);
3784:             }
3785:         } else {
3786:             $pinfo = openssl_pkey_get_details($privKey);
3787:             $hash = hash('sha256', $signHeader);
3788:             //'Magic' constant for SHA256 from RFC3447
3789:             //@link https://tools.ietf.org/html/rfc3447#page-43
3790:             $t = '3031300d060960864801650304020105000420' . $hash;
3791:             $pslen = $pinfo['bits'] / 8 - (strlen($t) / 2 + 3);
3792:             $eb = pack('H*', '0001' . str_repeat('FF', $pslen) . '00' . $t);
3793: 
3794:             if (openssl_private_encrypt($eb, $signature, $privKey, OPENSSL_NO_PADDING)) {
3795:                 openssl_pkey_free($privKey);
3796:                 return base64_encode($signature);
3797:             }
3798:         }
3799:         openssl_pkey_free($privKey);
3800:         return '';
3801:     }
3802: 
3803:     /**
3804:      * Generate a DKIM canonicalization header.
3805:      * @access public
3806:      * @param string $signHeader Header
3807:      * @return string
3808:      */
3809:     public function DKIM_HeaderC($signHeader)
3810:     {
3811:         $signHeader = preg_replace('/\r\n\s+/', ' ', $signHeader);
3812:         $lines = explode("\r\n", $signHeader);
3813:         foreach ($lines as $key => $line) {
3814:             list($heading, $value) = explode(':', $line, 2);
3815:             $heading = strtolower($heading);
3816:             $value = preg_replace('/\s{2,}/', ' ', $value); // Compress useless spaces
3817:             $lines[$key] = $heading . ':' . trim($value); // Don't forget to remove WSP around the value
3818:         }
3819:         $signHeader = implode("\r\n", $lines);
3820:         return $signHeader;
3821:     }
3822: 
3823:     /**
3824:      * Generate a DKIM canonicalization body.
3825:      * @access public
3826:      * @param string $body Message Body
3827:      * @return string
3828:      */
3829:     public function DKIM_BodyC($body)
3830:     {
3831:         if ($body == '') {
3832:             return "\r\n";
3833:         }
3834:         // stabilize line endings
3835:         $body = str_replace("\r\n", "\n", $body);
3836:         $body = str_replace("\n", "\r\n", $body);
3837:         // END stabilize line endings
3838:         while (substr($body, strlen($body) - 4, 4) == "\r\n\r\n") {
3839:             $body = substr($body, 0, strlen($body) - 2);
3840:         }
3841:         return $body;
3842:     }
3843: 
3844:     /**
3845:      * Create the DKIM header and body in a new message header.
3846:      * @access public
3847:      * @param string $headers_line Header lines
3848:      * @param string $subject Subject
3849:      * @param string $body Body
3850:      * @return string
3851:      */
3852:     public function DKIM_Add($headers_line, $subject, $body)
3853:     {
3854:         $DKIMsignatureType = 'rsa-sha256'; // Signature & hash algorithms
3855:         $DKIMcanonicalization = 'relaxed/simple'; // Canonicalization of header/body
3856:         $DKIMquery = 'dns/txt'; // Query method
3857:         $DKIMtime = time(); // Signature Timestamp = seconds since 00:00:00 - Jan 1, 1970 (UTC time zone)
3858:         $subject_header = "Subject: $subject";
3859:         $headers = explode($this->LE, $headers_line);
3860:         $from_header = '';
3861:         $to_header = '';
3862:         $date_header = '';
3863:         $current = '';
3864:         foreach ($headers as $header) {
3865:             if (strpos($header, 'From:') === 0) {
3866:                 $from_header = $header;
3867:                 $current = 'from_header';
3868:             } elseif (strpos($header, 'To:') === 0) {
3869:                 $to_header = $header;
3870:                 $current = 'to_header';
3871:             } elseif (strpos($header, 'Date:') === 0) {
3872:                 $date_header = $header;
3873:                 $current = 'date_header';
3874:             } else {
3875:                 if (!empty($$current) && strpos($header, ' =?') === 0) {
3876:                     $$current .= $header;
3877:                 } else {
3878:                     $current = '';
3879:                 }
3880:             }
3881:         }
3882:         $from = str_replace('|', '=7C', $this->DKIM_QP($from_header));
3883:         $to = str_replace('|', '=7C', $this->DKIM_QP($to_header));
3884:         $date = str_replace('|', '=7C', $this->DKIM_QP($date_header));
3885:         $subject = str_replace(
3886:             '|',
3887:             '=7C',
3888:             $this->DKIM_QP($subject_header)
3889:         ); // Copied header fields (dkim-quoted-printable)
3890:         $body = $this->DKIM_BodyC($body);
3891:         $DKIMlen = strlen($body); // Length of body
3892:         $DKIMb64 = base64_encode(pack('H*', hash('sha256', $body))); // Base64 of packed binary SHA-256 hash of body
3893:         if ('' == $this->DKIM_identity) {
3894:             $ident = '';
3895:         } else {
3896:             $ident = ' i=' . $this->DKIM_identity . ';';
3897:         }
3898:         $dkimhdrs = 'DKIM-Signature: v=1; a=' .
3899:             $DKIMsignatureType . '; q=' .
3900:             $DKIMquery . '; l=' .
3901:             $DKIMlen . '; s=' .
3902:             $this->DKIM_selector .
3903:             ";\r\n" .
3904:             "\tt=" . $DKIMtime . '; c=' . $DKIMcanonicalization . ";\r\n" .
3905:             "\th=From:To:Date:Subject;\r\n" .
3906:             "\td=" . $this->DKIM_domain . ';' . $ident . "\r\n" .
3907:             "\tz=$from\r\n" .
3908:             "\t|$to\r\n" .
3909:             "\t|$date\r\n" .
3910:             "\t|$subject;\r\n" .
3911:             "\tbh=" . $DKIMb64 . ";\r\n" .
3912:             "\tb=";
3913:         $toSign = $this->DKIM_HeaderC(
3914:             $from_header . "\r\n" .
3915:             $to_header . "\r\n" .
3916:             $date_header . "\r\n" .
3917:             $subject_header . "\r\n" .
3918:             $dkimhdrs
3919:         );
3920:         $signed = $this->DKIM_Sign($toSign);
3921:         return $dkimhdrs . $signed . "\r\n";
3922:     }
3923: 
3924:     /**
3925:      * Detect if a string contains a line longer than the maximum line length allowed.
3926:      * @param string $str
3927:      * @return boolean
3928:      * @static
3929:      */
3930:     public static function hasLineLongerThanMax($str)
3931:     {
3932:         //+2 to include CRLF line break for a 1000 total
3933:         return (boolean)preg_match('/^(.{'.(self::MAX_LINE_LENGTH + 2).',})/m', $str);
3934:     }
3935: 
3936:     /**
3937:      * Allows for public read access to 'to' property.
3938:      * @note: Before the send() call, queued addresses (i.e. with IDN) are not yet included.
3939:      * @access public
3940:      * @return array
3941:      */
3942:     public function getToAddresses()
3943:     {
3944:         return $this->to;
3945:     }
3946: 
3947:     /**
3948:      * Allows for public read access to 'cc' property.
3949:      * @note: Before the send() call, queued addresses (i.e. with IDN) are not yet included.
3950:      * @access public
3951:      * @return array
3952:      */
3953:     public function getCcAddresses()
3954:     {
3955:         return $this->cc;
3956:     }
3957: 
3958:     /**
3959:      * Allows for public read access to 'bcc' property.
3960:      * @note: Before the send() call, queued addresses (i.e. with IDN) are not yet included.
3961:      * @access public
3962:      * @return array
3963:      */
3964:     public function getBccAddresses()
3965:     {
3966:         return $this->bcc;
3967:     }
3968: 
3969:     /**
3970:      * Allows for public read access to 'ReplyTo' property.
3971:      * @note: Before the send() call, queued addresses (i.e. with IDN) are not yet included.
3972:      * @access public
3973:      * @return array
3974:      */
3975:     public function getReplyToAddresses()
3976:     {
3977:         return $this->ReplyTo;
3978:     }
3979: 
3980:     /**
3981:      * Allows for public read access to 'all_recipients' property.
3982:      * @note: Before the send() call, queued addresses (i.e. with IDN) are not yet included.
3983:      * @access public
3984:      * @return array
3985:      */
3986:     public function getAllRecipientAddresses()
3987:     {
3988:         return $this->all_recipients;
3989:     }
3990: 
3991:     /**
3992:      * Perform a callback.
3993:      * @param boolean $isSent
3994:      * @param array $to
3995:      * @param array $cc
3996:      * @param array $bcc
3997:      * @param string $subject
3998:      * @param string $body
3999:      * @param string $from
4000:      */
4001:     protected function doCallback($isSent, $to, $cc, $bcc, $subject, $body, $from)
4002:     {
4003:         if (!empty($this->action_function) && is_callable($this->action_function)) {
4004:             $params = array($isSent, $to, $cc, $bcc, $subject, $body, $from);
4005:             call_user_func_array($this->action_function, $params);
4006:         }
4007:     }
4008: }
4009: 
4010: /**
4011:  * PHPMailer exception handler
4012:  * @package PHPMailer
4013:  */
4014: class phpmailerException extends Exception
4015: {
4016:     /**
4017:      * Prettify error message output
4018:      * @return string
4019:      */
4020:     public function errorMessage()
4021:     {
4022:         $errorMsg = '<strong>' . $this->getMessage() . "</strong><br />\n";
4023:         return $errorMsg;
4024:     }
4025: }
4026: 
API documentation generated by ApiGen