2019 Failed to call to new PHPMailer that does not create an instance of PHPMailer Version 6.0.7 - phpmailer

Failed to call new PHPMailer and does not create an instance of PHPMailer. The setting of $mail->SMTPDebug creates a stdClass instance, and then calling a non-existent method on it (isSMTP) fails. So it's all down to that instance creation failure. PHPMailer Version 6.0.7 Live Hosting Service
I have tried $mail = new stdClass();
or $mail = NULL; This is symptom fix but does not the cause and causes my page to send an email every time it loads.
<?php
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;
require 'PHPMailer/Exception.php';
require 'PHPMailer/PHPMailer.php';
require 'PHPMailer/SMTP.php';
if(isset($_POST[‘submit’]))
$mail = new PHPMailer(true);
$mail->SMTPDebug = 2; // 0 = off (for production use) - 1 = client messages - 2 = client and server messages
$mail->isSMTP();
$mail->Host = 'mail.email.org';
$mail->SMTPSecure = 'ssl'; <-- Recommend by the hosting service
$mail->Port = 465; <-- Recommend by the hosting service <--Hosting Service Docs verify this
$mail->SMTPAuth = true;
$mail->Username = 'Mail#email.org';
$mail->Password = 'Using the correct Password';
$to = 'Mail#email.org'; <-- sending this to myself
$from = 'Mail#email.org'; <--sending to myself
$first_name = ((isset($_POST['FirstName']))&&(!is_null($_POST['FirstName'])))? $_POST['FirstName']:'';
$last_name = ((isset($_POST['LastName']))&&(!is_null($_POST['LastName'])))? $_POST['LastName']:'';
$email = ((isset($_POST['Email']))&&(!is_null($_POST['Email'])))? $_POST['Email']:'';
$age = ((isset($_POST['Age']))&&(!is_null($_POST['Age'])))? $_POST['Age']:'';
$student = ((isset($_POST['Student']))&&(!is_null($_POST['Student'])))? $_POST['Student']:'';
$agree18 = ((isset($_POST['Agree18']))&&(!is_null($_POST['Agree18'])))? $_POST['Agree18']:'';
/* Set the mail sender. */
$mail->setFrom( $to , 'Research');
/* Add a recipient. */
$mail->addAddress( $_POST['Email'] , 'Research');
/* Set the subject. */
$mail->Subject = 'Learn More about Research Requested';
$mail->isHTML(TRUE);
$mail->Body = '<html> "First Name:" . $first_name . " Last Name:" . $last_name . " Email:". $email . " Age:" . $age . " Student:" . $student . " Agree18:" . $agree18 . ""
</html>';
$mail->AltBody = ' "First Name:" . $first_name . " Last Name:" . $last_name . " Email:". $email . " Age:" . $age . " Student:" . $student . " Agree18:" . $agree18 . ""
';
if($mail->send()){
$msg="Your email msg has been send";
}else{
$msg="mail msg has not been send";
echo 'Mailer Error: ' . $mail->ErrorInfo;
}
?>
Hope to find a solution to why it's failing.
Removed all my code, Performed what synchro stated and got this:
object(PHPMailer\PHPMailer\PHPMailer)#1 (74) { ["Priority"]=> NULL ["CharSet"]=> string(10) "iso-8859-1" ["ContentType"]=> string(10) "text/plain" ["Encoding"]=> string(4) "8bit" ["ErrorInfo"]=> string(0) "" ["From"]=> string(14) "root#localhost" ["FromName"]=> string(9) "Root User" ["Sender"]=> string(0) "" ["Subject"]=> string(0) "" ["Body"]=> string(0) "" ["AltBody"]=> string(0) "" ["Ical"]=> string(0) ""
["MIMEBody":protected]=> string(0) "" ["MIMEHeader":protected]=> string(0) "" ["mailHeader":protected]=> string(0) "" ["WordWrap"]=> int(0) ["Mailer"]=> string(4) "mail" ["Sendmail"]=> string(18) "/usr/sbin/sendmail" ["UseSendmailOptions"]=> bool(true) ["ConfirmReadingTo"]=> string(0) "" ["Hostname"]=> string(0) "" ["MessageID"]=> string(0) "" ["MessageDate"]=> string(0) "" ["Host"]=> string(9) "localhost" ["Port"]=> int(25)
"Helo"]=> string(0) "" ["SMTPSecure"]=> string(0) "" ["SMTPAutoTLS"]=> bool(true) ["SMTPAuth"]=> bool(false) ["SMTPOptions"]=> array(0) { } ["Username"]=> string(0) "" ["Password"]=> string(0) "" ["AuthType"]=> string(0) "" ["oauth":protected]=> NULL ["Timeout"]=> int(300) ["dsn"]=> string(0) "" ["SMTPDebug"]=> int(0) ["Debugoutput"]=> string(4) "html" ["SMTPKeepAlive"]=> bool(false) ["SingleTo"]=> bool(false)
["SingleToArray":protected]=> array(0) { } ["do_verp"]=> bool(false) ["AllowEmpty"]=> bool(false) ["DKIM_selector"]=> string(0) "" ["DKIM_identity"]=> string(0) "" ["DKIM_passphrase"]=> string(0) "" ["DKIM_domain"]=> string(0) "" ["DKIM_copyHeaderFields"]=> bool(true) ["DKIM_extraHeaders"]=> array(0) { } ["DKIM_private"]=> string(0) "" ["DKIM_private_string"]=> string(0) "" ["action_function"]=> string(0) ""
"XMailer"]=> string(0) "" ["smtp":protected]=> NULL ["to":protected]=> array(0) { } ["cc":protected]=> array(0) { } ["bcc":protected]=> array(0) { } ["ReplyTo":protected]=> array(0) { } ["all_recipients":protected]=> array(0) { } ["RecipientsQueue":protected]=> array(0) { } ["ReplyToQueue":protected]=> array(0) { } ["attachment":protected]=> array(0) { } ["CustomHeader":protected]=> array(0) { }
"lastMessageID":protected]=> string(0) "" ["message_type":protected]=> string(0) "" ["boundary":protected]=> array(0) { } ["language":protected]=> array(0) { } ["error_count":protected]=> int(0) ["sign_cert_file":protected]=> string(0) "" ["sign_key_file":protected]=> string(0) "" ["sign_extracerts_file":protected]=> string(0) "" ["sign_key_pass":protected]=> string(0) "" ["exceptions":protected]=> bool(false) ["uniqueid":protected]=> string(0) ""

This is a duplicate of your previous question with a different title.
When you have code that doesn't work, cut it back to a minimal example so that you exclude opportunities for ambiguity, and enable verbose, visible error reporting:
use PHPMailer\PHPMailer\PHPMailer;
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
require 'PHPMailer/PHPMailer.php';
$mail = new PHPMailer;
var_dump($mail);
If that doesn't work, a more complex script isn't going to work either. For this to fail, I would suspect that there is something severely wrong with your PHP installation, and at the very least I would expect to see some warnings logged.

You forgot a bracket after condition with isset($_POST[...]).
if(isset($_POST['submit'])) {
// ^^
$mail = new PHPMailer(true);
$mail->SMTPDebug = 2; // 0 = off (for production use) - 1 = client messages - 2 = client and server messages
$mail->isSMTP();
...
}
// of course, don'f forget to add a closing one too here.

Fixed <-- Thanks to Synchro --> & Thanks Panthers for the input
Added use PHPMailer\PHPMailer\SMTP; <- This fixed most of my issues but not always required per Synchro
For working example with PHPMailer 6.0.7 look for Synchro's
This is a duplicate of your previous question with a different title Link.

Related

Azure table storage REST Query doesn't show new entries

I'm building a query for a Azure Storage Account(tables in this case). I try to receive the last log entries of the last day.
The filter looks like this in the storage query builder:
{
"filter": [
{
"id": "{ID}",
"andOr": "And",
"field": "TIMESTAMP",
"type": "DateTime",
"operator": ">=",
"value": "datetime'2019-11-18T10:08:41.296Z'",
"timeValue": "Last 24 hours",
"timestampType": "time",
"customTimestamp": {
"lastNumber": 7,
"lastTimeUnit": "Days"
},
"isLocal": true
}
],
"select": null,
"group": {
"id": "{ID}",
"children": [
"{CHILD}"
]
},
"top": null,
"filterType": "Query Builder",
"fileVersion": 0.2
}
This query returnes all the entries from the last day.
I tried to use this filter in the Azure REST API call. in a powershell function like this:
function GetTableEntityAll($TableName) {
$version = "2017-04-17"
$resource = "$tableName()"
$DST = [DateTime]::Today.AddDays(-1)
$table_url = "https://$storageAccount.table.core.windows.net/$resource"+ '?$filter=Timestamp gt datetime' + "'"+ $DST.ToString("s") + "'"
write-host $table_url
$GMTTime = (Get-Date).ToUniversalTime().toString('R')
$stringToSign = "$GMTTime`n/$storageAccount/$resource"
$hmacsha = New-Object System.Security.Cryptography.HMACSHA256
$hmacsha.key = [Convert]::FromBase64String($accesskey)
$signature = $hmacsha.ComputeHash([Text.Encoding]::UTF8.GetBytes($stringToSign))
$signature = [Convert]::ToBase64String($signature)
$headers = #{
'x-ms-date' = $GMTTime
Authorization = "SharedKeyLite " + $storageAccount + ":" + $signature
"x-ms-version" = $version
Accept = "application/json;odata=fullmetadata"
}
$item = Invoke-RestMethod -Method GET -Uri $table_url -Headers $headers -ContentType application/json
return $item.value
}
The URL I generate with this is:
https://{Accountname}.table.core.windows.net/{Tablename}()?$filter=Timestamp gt datetime'2019-11-18T00:00:00'
This doesn't return any records. I also tried to encode the url but that doesns't work either. If I change the datetime to 2016 I receive the first few records.
Azure documentation: https://learn.microsoft.com/en-us/rest/api/storageservices/querying-tables-and-entities
Any ideas?

Are there any popular and/or efficient recursive find and replace algorithms?

I am currently developing an application that requires the renaming of music files from a variety of variations such as
Artist - Title feat featuring artist, etc
Or
Artist - Title ft featuring artist, etc
Or
Artist - Title (feat. Featuring artist, etc
To
Artist - Title (ft. featuring artist, etc)
I think you get the idea.
My current hacky way to do this:
private void FindAndReplace()
{
try
{
var replaceList = new Dictionary<string, string>
{
{"[", "("},
{"]", ")"},
{"(Official Audio)", ""},
{"(Audio)", ""},
{"OFFICIAL", ""},
{"Official", ""},
{"(Video)", ""},
{"Video)", ""},
{"(video)", ""},
{"video)", ""},
{"(Lyric","" },
{ " Featuring ", " (ft. "},
{",)", ")"},
{" FEAT ", " (FEAT "},
{" Feat ", " (FEAT "},
{" Feat. ", " (FEAT "},
{"(Feat.", "(ft."},
{"(FEAT", "(feat"},
{"( Music",""},
{"(feat", "(ft"},
{"FEAT ", "ft"},
{"( )", ""},
{"()", ""},
{"(|", ""},
{"( |", ""},
{"( )", ""},
{"FT ", "ft. "},
{"Ft ", "ft. "},
{"(Explicit)", ""},
{"ft ", "ft. "},
{" Ft. ", " (ft. "},//[ FT. , (ft. ]
{" FT. ", " (ft. "},//[ FT. , (ft. ]
{" FT", " (ft"},//[ FT, (ft]
{"(FT ", "(ft. "},
{" (ft ", " (ft."},
{" (Ft ", "(ft. "}
};
while (true)
{
var reiterate = false;
foreach (var vari in replaceList)
{
if (FileName.ToLower().Contains(vari.Key.ToLower()))
{
reiterate = true;
}
}
if (reiterate)
foreach (var replaceItem in replaceList.Where(replaceItem => FileName.ToLower().Contains(replaceItem.Key.ToLower()))
)
{
if (FileName.Contains(replaceItem.Key))
FileName = FileName.Replace(replaceItem.Key, replaceItem.Value);
else
FileName = FileName.Replace(replaceItem.Key.ToLower(), replaceItem.Value);
}
if (reiterate) continue;
break;
}
}
catch (Exception ex)
{
}
}
Note that there are a multitude of things that could need fixing in the filename.
I occasionally run into errors with this method and they all stem from the ordering of the replace dictionary. Is there some more efficient and cleaner way to achieve my goal?
You could merge rules by using regular expressions.
e.g
replaceAll("(?i)[\\s\\(]*fe?a?t\\.?[\\s]", " (ft. ")
With this, you could replace all/most of your rules around the 'feature' part.

Docusign Customer Document Data

With docusign is there a way to send custom data to the document.
The use-case we have is that we are having customers sign an embedded form. We populate all of their data from our Database.
So the main contract is the same but we need to send some values such as contract number, name, address, and price to the document we are having signed. What would be the best way to accomplish this?
I have seen customer tags mentioned for this purpose but it seems like we can only do this in classic view which makes it seem like this will not be a supported feature in the new version.
Update:
I am still at a stand still on this issue.
I have tried doing what was suggested and setting textCustomFields
However, no matter what I pass in the label I set up does not show up.
For example.
I have the Name field on my Document and I also have a Text Field with the Data Label of: contractid
Then I try passing the data in in my envelope as described in the documentation (I have yet to find an example of this anywhere)
string requestBody =
"<envelopeDefinition xmlns=\"http://www.docusign.com/restapi\">" +
"<status>sent</status>" +
"<emailSubject>DocuSign API - Embedded Signing example</emailSubject>" +
"<templateId>" + templateId + "</templateId>" +
"<templateRoles>" +
"<templateRole>" +
"<email>" + recipientEmail + "</email>" +
"<name>" + recipientName + "</name>" +
"<roleName>" + templateRole + "</roleName>" +
"<clientUserId>1</clientUserId>" + // user-configurable
"</templateRole>" +
"</templateRoles>" +
"<customFields>" +
"<textCustomFields>" +
"<fieldId>contractid</fieldId>" +
"<name>contractid</name>" +
"<required>true</required>" +
"<show>true</show>" +
"<value>123</value>" +
"</textCustomFields>" +
"</customFields>" +
"</envelopeDefinition>";
The name field shows up correctly in the contract, but that is a custom field predefined by Docusign
However, the contractid field just shows blank as no data has been passed into it.
I even tried adding the information into the call to my view for when I show the embeded contract and that does not do anything either.
I may be going about this the wrong way but so far I can find no good documentation on how to send custom data into the contract via the REST API.
Edit:
Here is a Screen Shot of my setup and I have attempted to add the Text Tabs into both the envelope and the document view request.
I have to say I have worked with Multiple Rest API's including working with Twilio, Phaxio, Twitter and this Rest API implementation seems to be the most confusing I have every ran across as far as what does what
We are working through our DocuSign implementation and are able to do what you are looking for with textTabs added to the signers object. I've attached my POC code in PowerShell that shows the tabs being formatted.
We generate contracts in Word 2013 and use anchors to place everything. The source document will have something like //SIGNATURE// in the text, but before release it is highlighted and changed to white font so the final contract renders nicely in DocuSign.
Results in this (except I chopped out the name and title)
Put your API Key and credentials into the logon function and set up the recipient info at the top. The script creates and sends an envelope with document called "contract.docx"
[string]$recipientEmail = "mr.mann#bluesbrothers.com"
[string]$recipientName = "Mr. Mann"
[string]$recipientFirstName = "Mann"
[string]$recipientTitle = "CEO, Mann, Inc."
function boundry {
[System.Guid]::NewGuid().ToString()
}
function encodeFile {
param ([string]$fileName)
[System.Convert]::ToBase64String([IO.File]::ReadAllBytes((Resolve-Path $fileName).ProviderPath))
}
function logonParams {
[string] $userName = 'YOUR USER NAME'
[string] $password = 'YOUR PASSWORD'
[string] $integratorKey = 'YOUR INTEGRATOR KEY'
#"
{
"Username" : "$userName",
"Password" : "$password",
"IntegratorKey" : "$integratorKey"
}
"#
}
function logon {
[string] $loginURL = 'https://demo.docusign.net/restapi/v2/login_information'
$headers =
#{
"X-DocuSign-Authentication"=$(logonParams);
"accept"="application/json";
"content-type"="application/json";
}
$r = Invoke-WebRequest -uri $loginURL -headers $headers -method GET
$responseInfo = $r.content | ConvertFrom-Json
$baseURL = $responseInfo.loginAccounts.baseURL
$baseURL
}
function createEnvelope {
param ([string]$contractFile,
[string]$baseURL
)
[string]$boundry = boundry
$headers =
#{
"X-DocuSign-Authentication"=$(logonParams);
"accept"="application/json";
"content-type"="multipart/form-data; boundary=$boundry";
}
[string]$formData = #"
--$boundry
Content-Type: application/json
{
"status":"sent",
"emailBlurb":"$recipientFirstName, Here is a test contract that I uploaded to DocuSign and routed through their webservice API.",
"emailSubject": "Test Contract $(date)",
"authoritativeCopy" : "true",
"documents": [
{
"name": "$contractFile",
"documentId":"1",
"order":"1"
}
],
"recipients": {
"signers" : [{
"email" : "$recipientEmail",
"name" : "$recipientName",
"title" : "$recipientTitle",
"recipientId":"1",
"tabs" : {
"signHereTabs" : [{
"anchorString" : "//SIGNATURE//"
}],
"fullNameTabs" : [{
"anchorString" : "//SIGNATURE_NAME//",
"font" : "Calibri",
"fontSize" : "Size11",
"anchorYOffset" : -10
}],
"titleTabs" : [{
"anchorString" : "//SIGNATURE_TITLE//",
"font" : "Calibri",
"fontSize" : "Size11",
"anchorYOffset" : -10
}],
"dateTabs" : [{
"anchorString" : "//SIGNATURE_DATE//",
"font" : "Calibri",
"fontSize" : "Size11",
"anchorYOffset" : -10
}],
"textTabs" : [
{
"anchorString" : "//INVOICE_NAME//",
"font" : "Calibri",
"fontSize" : "Size11",
"anchorYOffset" : -10,
"value" : "My Invoice Name",
},
{
"anchorString" : "//INVOICE_ADDRESS1//",
"font" : "Calibri",
"fontSize" : "Size11",
"anchorYOffset" : -10,
"value" : "My Invoice Address 1",
},
{
"anchorString" : "//INVOICE_ADDRESS2//",
"font" : "Calibri",
"fontSize" : "Size11",
"anchorYOffset" : -10,
"value" : "My Invoice Address 2",
},
{
"anchorString" : "//INVOICE_ADDRESS3//",
"font" : "Calibri",
"fontSize" : "Size11",
"anchorYOffset" : -10,
"value" : "My Invoice Address 3",
},
{
"anchorString" : "//INVOICE_EMAIL//",
"font" : "Calibri",
"fontSize" : "Size11",
"anchorYOffset" : -10,
"value" : "somebody#somewhere.com"
}
],
}
}]
}
}
--$boundry
Content-Type: application/vnd.openxmlformats-officedocument.wordprocessingml.document
Content-Transfer-Encoding: base64
Content-Disposition: file; filename="$mainFile";documentid=1
$(encodeFile $contractFile)
--$boundry--
"#
$envelopeURL = "$baseURL/envelopes"
Invoke-WebRequest -uri $envelopeURL -headers $headers -body $formData -method POST
}
$baseURL = logon
createEnvelope "contract.docx" $baseURL
For those using XML and trying to auto fill in the data
string requestBody =
"<envelopeDefinition xmlns=\"http://www.docusign.com/restapi\">" +
"<status>sent</status>" +
"<emailSubject>DocuSign API - Embedded Signing example</emailSubject>" +
"<templateId>" + templateId + "</templateId>" +
"<templateRoles>" +
"<templateRole>" +
"<email>" + recipientEmail + "</email>" +
"<name>" + recipientName + "</name>" +
"<roleName>" + templateRole + "</roleName>" +
"<clientUserId>1</clientUserId>" + // user-configurable
"<tabs>" +
"<textTabs>" +
"<text>" +
"<anchorString>follows:</anchorString>" +
"<value>Initial Data Goes</value>" +
"</text>" +
"</textTabs>" +
"</tabs>" +
"</templateRole>" +
"</templateRoles>" +
"</envelopeDefinition>";
Then anywhere in your document you have the words follows: you will have the text show up and you can modify it to display it where you want using other fields.
This would be done through the DocuSign API. You can build a template based on that contract and add the fields that needs data in them. Then when creating the envelope you can set the data that is populated within those fields.
More info can be found here.
EDIT:
Sample code can be found here
Custom Fields refer to Envelope Custom Fields which are an element that can be used to record information about the envelope, help search for envelopes and track information, not for tabs.
You'll want textTab:
<textTabs>
<text>
<anchorIgnoreIfNotPresent>sample string 35</anchorIgnoreIfNotPresent>
<anchorString>sample string 31</anchorString>
<anchorUnits>sample string 34</anchorUnits>
<anchorXOffset>sample string 32</anchorXOffset>
<anchorYOffset>sample string 33</anchorYOffset>
<conditionalParentLabel>sample string 39</conditionalParentLabel>
<conditionalParentValue>sample string 40</conditionalParentValue>
<documentId>sample string 26</documentId>
<pageNumber>sample string 28</pageNumber>
<recipientId>sample string 27</recipientId>
<tabId>sample string 36</tabId>
<templateLocked>sample string 37</templateLocked>
<templateRequired>sample string 38</templateRequired>
<xPosition>sample string 29</xPosition>
<yPosition>sample string 30</yPosition>
<bold>sample string 21</bold>
<font>sample string 20</font>
<fontColor>sample string 24</fontColor>
<fontSize>sample string 25</fontSize>
<italic>sample string 22</italic>
<tabLabel>sample string 19</tabLabel>
<underline>sample string 23</underline>
<concealValueOnDocument>sample string 16</concealValueOnDocument>
<disableAutoSize>sample string 17</disableAutoSize>
<locked>sample string 15</locked>
<maxLength>18</maxLength>
<name>sample string 10</name>
<originalValue>sample string 12</originalValue>
<required>sample string 14</required>
<value>sample string 11</value>
<width>13</width>
<requireAll>sample string 9</requireAll>
<requireInitialOnSharedChange>sample string 7</requireInitialOnSharedChange>
<senderRequired>sample string 8</senderRequired>
<shared>sample string 6</shared>
<validationMessage>sample string 5</validationMessage>
<validationPattern>sample string 4</validationPattern>
<formula>sample string 3</formula>
<height>1</height>
<isPaymentAmount>sample string 2</isPaymentAmount>
</text>
</textTabs>

Laravel Excel Cannot use object of type stdClass as array

I'm having to use DB::select instead of calling a Model because my data structure is too complex.
My main SQL query is;
/* main mysql query */
$sql = "SELECT t1.* FROM `contracts`.`payments` as t1 LEFT JOIN `postcodes`.`" . $postcode_dataset . "` AS t2 ON t1.`VendorZIP` = t2.`postcode` WHERE ";
foreach ($unserialized_input as $key => $value) {
$sql .= "t2." . $key . " IN ('".implode("', '", $unserialized_input[$key])."') OR ";
}
$sql = rtrim($sql, " OR ");
$payments = DB::select($sql);
I am trying to use Maatwebsite Excel to export the result by doing this;
Excel::create('SME_Payments_Export-U', function($excel) use ($payments) {
$excel->sheet('Excel sheet', function($sheet) use ($payments) {
$sheet->setOrientation('landscape');
$sheet->fromArray($payments);
});
})->export('csv');
But I get the error;
Cannot use object of type stdClass as array
Here is a sample of my var_dump;
array(176) {
[0]=>
object(stdClass)#302 (4) {
["Fiscal Year"]=>
string(5) "13/14"
["Contract Number"]=>
string(0) ""
["Foreign Ind"]=>
string(1) "N"
["Valued or Running"]=>
string(1) "R"
}
[1]=>
object(stdClass)#304 (4) {
["Fiscal Year"]=>
string(5) "13/14"
["Contract Number"]=>
string(0) ""
["Foreign Ind"]=>
string(1) "Y"
["Valued or Running"]=>
string(1) "V"
}
[2]=>
object(stdClass)#305 (4) {
["Fiscal Year"]=>
string(5) "13/14"
["Contract Number"]=>
string(0) ""
["Foreign Ind"]=>
string(1) "N"
["Valued or Running"]=>
string(1) "R"
}
How can I convert payments?
As per documentation you need to transform array of objects to array of arrays before passing it to fromArray() method:
foreach ($payments as &$payment) {
$payment = (array)$payment;
}
$sheet->fromArray($payments);
I have faced same problem and what worked for me best is:
$payments = json_decode( json_encode($payments), true);
This will convert object/array to array and make it usable.

ldap password change with Expect Module

I don't have a super skill in perl. But, I did this both scripts for changing LDAP password by the users.
The first script:
#!/usr/bin/perl -w
use strict;
use Expect;
my $user= getpwuid( $< );
print "Enter your old password :" ;
my $oldpassword = <STDIN>;
chomp($oldpassword);
print "Enter you new password :";
my $newpassword = <STDIN>;
chomp($newpassword);
print "Running ' passwd ${user}'\n";
my $exp = Expect->spawn("passwd") or die "Can t acces to passwd \n";
unless ($exp->expect(1, "Enter login\(LDAP\) password:")) {} ;
print $exp "${oldpassword}\r" ;
unless ($exp->expect(1, "New password:")) {} ;
print $exp "${newpassword}\r" ;
unless ($exp->expect(1, "Re-enter new password:")) {} ;
print $exp "${newpassword}\r" ;
$exp->soft_close();
The second script:
#!/usr/bin/perl -w
use strict;
use Expect;
my $user= getpwuid( $< );
print "Enter your old password :" ;
my $oldpassword = <STDIN>;
chomp($oldpassword);
print "Enter your new password :";
my $newpassword = <STDIN>;
chomp($newpassword);
print "Running ' passwd ${user}'\n";
my $spawn_ok;
my $exp = Expect->spawn("passwd") or die "Can t acces to passwd \n";
$exp->expect(1,
[qr 'Enter login\(LDAP\) password:' ,
sub {
$spawn_ok = 1;
my $fh = shift;
$fh->send("${oldpassword}\n");
print "sent '${oldpassword}'\n";
exp_continue;
}
],
[eof =>
sub {
if ($spawn_ok) {
die "ERROR: premature EOF in login.\n";
} else {
die "ERROR: could not spawn old password.\n";
}
}
],
['New password: ' ,
sub {
my $fh =shift ;
$fh->send("${newpassword}\n");
print "sent '${newpassword}'\n";
exp_continue;
}
],
['Re-enter new password:' ,
sub {
my $fh =shift ;
$fh->send("${newpassword}\n");
print "sent '${newpassword}'\n";
exp_continue;
}
]
);
I don't know what is the better between them. But they work.
Actually my script are working same if the old password is wrong. I would like a control of the old password before the script continue, or maybe the script restarts if the old password is wrong. I thought about a loop, I tried to put is the booth scripts without success.
Could I've some help ?
Did you know about Net::Ldap module?
http://search.cpan.org/~gbarr/perl-ldap/lib/Net/LDAP/FAQ.pod#Ho_do_I_reset_a_user%27s_password_...
Without error checking!
use Net::LDAP;
my $ldap = Net::LDAP->new('ldaps://server.domain') or die "$#";
my $mesg = $ldap->bind('cn=Joe User,dc=perl,dc=ldap,dc=org',
password => 'oldPW');
my $rootdse = $ldap->root_dse();
if ($rootdse->supported_extension('1.3.6.1.4.1.4203.1.11.1') {
require Net::LDAP::Extension::SetPassword;
$mesg = $ldap->set_password(user => 'cn=Joe User,dc=perl,dc=ldap,dc=org',
oldpasswd => 'oldPW',
newpasswd => 'newPW');
}
else {
$mesg = $ldap->modify('cn=Joe User,dc=perl,dc=ldap,dc=org',
changes => [
delete => [ userPassword => $oldPW ]
add => [ userPassword => $newPW ] ]);
}
$ldap->unbind();

Resources