We have an autoscaling group in AWS where upon launch database connections timeout. This is a Zend Framework 1 app using PHP 7.0.22-0ubuntu0.16.04.1 on Ubuntu 16.04.3 LTS
The code is baked into the AMI but during launch a userdata script will pull from git and phing configure the app. The database domain hasn't changed in years, the configure is mostly to take care of which elasticache instance to use. In other words, the baked in code already has the database configured and just gets overwritten with same value during configure step.
Once the ec2 instance is in the ELB, it begins getting hit on /health-check to see if things are OK by the load balancer. Inside this controller is the following code:
public function healthCheckAction() {
try {
/* #var $DBConn Zend_Db_Adapter_Pdo_Mysql */
$DBConn = Zend_Registry::get('multidb')->getDb();
// test guide service (most likely will be from memcache, unlikely to hit db)
$guideService = $this->_apiGuideService();
$guideService->isLoaded();
// this line fails and throws an exception
// I put host in here just so an error would include it in throw during this phase instead of catch phase (where it works)
// test raw db connection
$dbh = new PDO("mysql:host={$DBConn->getConfig()['host']};dbname={$DBConn->getConfig()['dbname']}", $DBConn->getConfig()['username'], $DBConn->getConfig()['password']);
$data = $dbh->query("SELECT '{$DBConn->getConfig()['host']}' as host, now()")->fetchObject();
// test database connectivity
// I put host in here just so an error would include it in throw during this phase instead of catch phase (where it works)
$sql = "SELECT '{$DBConn->getConfig()['host']}' as host, now()";
$DBConn->fetchRow($sql);
// test cache
/* #var $cache Zend_Cache_Core */
$cache = Zend_Registry::get('cachemanager')->getCache('default');
if (!$cache->load('health_check')) {
$cache->save(true, 'health_check');
}
echo 'Instance is healthy';
}
catch (Exception $e) {
header('HTTP/1.1 500 Internal Server Error');
echo 'Instance is unhealthy';
// get instance id
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'http://169.254.169.254/latest/meta-data/public-ipv4');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
// get instance ip
$ip = curl_exec($ch);
curl_setopt($ch, CURLOPT_URL, 'http://169.254.169.254/latest/meta-data/instance-id');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$instance = curl_exec($ch);
// email us some info
$message = "Instance $instance failed health check. ssh ubuntu#$ip to investigate<br><br>" . $e->getLine() . " " . $e->getCode() . "<br>" . $e->getMessage() . "<br>" . $e->getTraceAsString(). "<br><br>";
ob_start();
// this works and returns access denied, not timeout
$this->runCommand('mysql -u examplecom_platform -h sg-rds-example.us-east-1.rds.amazonaws.com');
echo "testing DB with php<br>";
try {
echo "write host: " . $DBConn->getConfig()['host'] . "<br>";
echo "read host: " . $DBConn->getConfig()['host'] . "<br>";
$dbh = new PDO("mysql:host={$DBConn->getConfig()['host']};dbname={$DBConn->getConfig()['dbname']}", $DBConn->getConfig()['username'], $DBConn->getConfig()['password']);
$data = $dbh->query('select now()')->fetchObject();
echo "query database without zend:<br>";
print_r($data);
// this line works and prints out
// stdClass Object
// (
// [now()] => 2018-01-09 14:47:12
// )
$dbh = null;
} catch (PDOException $e) {
print "Error: " . $e->getMessage() . "<br/>";
}
// this all work/show correct IP
$this->runCommand('nc -vz sg-rds-example.us-east-1.rds.amazonaws.com 3306');
$this->runCommand('host sg-rds-example.us-east-1.rds.amazonaws.com');
$this->runCommand('dig sg-rds-example.us-east-1.rds.amazonaws.com');
$debug = ob_get_contents();
ob_end_clean();
$message .= "<br><br>" . str_replace("\n", "<br>", $debug);
$mail = new Zend_Mail();
$mail->setSubject('[examplecom] Instance Failed Healthcheck v2')
->setFrom('noreply#example.com')
->addTo('alerts#example.com')
->setBodyHtml($message)
->send();
}
}
As I kept debugging things I would add more and more stuff to test the connection
The try statement throws an error of SQLSTATE[HY000] [2002] Connection timed out
But this exact same connection works in the catch and is able to query now() from the database.
This is where I am stumped, how could the same process timeout on first connection but work during the error catching?
Also I will only get 1 or 2 of these emails saying it cant connect, but then eventually by the time I can login to test some things it is working and connecting fine. Health-check reports happy and instance is kept in ELB.
Any ideas or suggestions to add more debugging?
Related
The below php code works well from a web server (i.e., where the sms server
is located) but not working well from a local machine with xampp or wamp.
The actual server is in godaddy
What am i missing out?
The code retrieves the connection details from a table which includes:
username, password, msisdn, and sender. When the message is eventually sent,
the message is flagged so that is is not sent again.
<?php
$id = 0;
$con=mysqli_connect("localhost","root","","afrcan_wp");
// Check connection
if (mysqli_connect_errno())
{
echo "Failed to connect to MySQL: " . mysqli_connect_error();
}
$sql="SELECT id,message,username,password,MSISDN,sender,messagestatus FROM outgoingsms where messagestatus = 'not sent' LIMIT 1";
if ($result=mysqli_query($con,$sql))
{
// Fetch one and one row
while ($row=mysqli_fetch_row($result))
{
$id=$row[0];
$text1=$row[1];
$username=$row[2];
$password=$row[3];
$to=$row[4];
$sender=$row[5];
$messagestatus=$row[6];
//$conn1=mysqli_connect("localhost","afrcan_wp","Sirhenry888","afrcan_wp");
$conn1 = new mysqli("localhost","root","","african_wp");
// Check connection
if ($conn1->connect_error) {
die("Connection failed: " . $conn1->connect_error);
}
$sql = "UPDATE outgoingsms SET messagestatus='sent' WHERE id=$id";
if ($conn1->query($sql) === TRUE) {
echo "Record updated successfully";
} else {
echo "Error updating record: " . $conn1->error;
}
$text = trim($text1);
$postUrl = "https://www.connectmedia.co.ke/user-board/?api";
$action="send";
$post = [
'action' => "$action",
'to' => array($to),
'username' => "$username",
'password' => "$password",
'sender' => "$sender",
'message' => urlencode("$text"),
];
$ch = curl_init($postUrl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post));
$response = curl_exec($ch);
curl_close($ch);
echo "$response";
//send messages
}
// Free result set
mysqli_free_result($result);
$conn1->close();
}
mysqli_close($con);
?>
Is it an issue with the code? internet connection?
Any assistance will be highly appreciated
if this works on a web server but doesn't work on your localhost , it maybe that CURL is having firewall issues . By default CURL uses the port 1080 . Check to see that that port is opn on your localhost or try changing the port by doing
curl_setopt ($ch, CURLOPT_PORT , 8089);
I'm using CURL to request large XML Files from an API.
To prevent memory leaks I use this CURL option to stream the data and send it to the function curlCallback:
curl_setopt($ch, CURLOPT_WRITEFUNCTION, array($splitter, 'curlCallback'));
In the curlCallback I prepare the incoming XML Stream and call the function below to store every main XML Node in the MySQL Database. Everything works well but:
I want to optimize the efficiency to store the data in the MySQL Database. This is the actual code:
public function processLine($str) {
$prdData = simplexml_load_string($str);
// connect to mysql db
$servername = "localhost";
$username = "";
$password = "";
$dbname = 'temp';
$db = new \PDO('mysql:host=' . $servername . ';dbname=' . $dbname . ';charset=utf8mb4',
$username,
$password,
array(
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
\PDO::ATTR_PERSISTENT => false
)
);
try {
$stmt = $db->prepare("INSERT IGNORE INTO Product (PRDNO, DSCRD ,DSCRF, DSCRLONGD, DSCRLONGF, PRTNO, SMCAT, DEL, BNAMD) VALUES (:prdno, :dscrd, :dscrf, :dscrlongd, :dscrlongf, :prtno, :smcat, :del, :bnamd)");
// MySQL Transaction
$db->beginTransaction();
$stmt->bindParam(':prdno', $prdData->PRDNO);
$stmt->bindParam(':dscrd', $prdData->DSCRD);
$stmt->bindParam(':dscrf', $prdData->DSCRF);
$stmt->bindParam(':dscrlongd', $prdData->DSCRLONGD);
$stmt->bindParam(':dscrlongf', $prdData->DSCRLONGF);
$stmt->bindParam(':prtno', $prdData->PRTNO);
$stmt->bindParam(':smcat', $prdData->SMCAT);
$stmt->bindParam(':del', $prdData->DEL);
$stmt->bindParam(':bnamd', $prdData->BNAMD);
$stmt->execute();
$db->commit();
} catch (PDOException $e) {
error_log(date("d.m.Y H:i:s") . ' | ' . $e->getMessage() . PHP_EOL, 3, '/var/www/html/log/import.log');
$db->rollBack();
}
}
How can I optimize this to just send one transaction including for example 100 Rows?
To generate/initiate a new vulnerability scan at SoftLayer, this works (for every server in an account):
require_once('SoapClient.class.php');
$apiUsername = "omitted";
$apiKey = "omitted";
$client = SoftLayer_SoapClient::getClient('SoftLayer_Account', null, $apiUsername, $apiKey);
$accountInfo = $client->getObject();
$hardware = $client->getHardware();
foreach ($hardware as $server){
$scanclient = SoftLayer_SoapClient::getClient('SoftLayer_Network_Security_Scanner_Request', '', $apiUsername, $apiKey);
$scantemplate = new stdClass();
$scantemplate->accountId = $accountInfo->id;
$scantemplate->hardwareId = $server->id;
$scantemplate->ipAddress = $server->primaryIpAddress;
try{
// Successfully creates new scan
$scan = $scanclient->createObject($scantemplate);
} catch (Exception $e){
echo $e->getMessage() . "\n\r";
}
}
When changing
$reportstatus = $scanclient->createObject($scantemplate);
to
$reportstatus = $scanclient->getReport($scantemplate);
The API responds with an error concerning "Object does not exist to execute method on.".
Would SoftLayer_Network_Security_Scanner_RequestInitParameters be required as per the docs? If so how do you define these "init parameters" and attach to the request for status or report?
http://sldn.softlayer.com/reference/services/SoftLayer_Network_Security_Scanner_Request/getReport
You need to set the init parameter using the Softlayer PHP client you can do that like this:
When you are creating the client:
$virtualGuestService = SoftLayer_SoapClient::getClient('SoftLayer_Virtual_Guest', $initParemter, $username, $key);
Or after creating the client:
$virtualGuestService = SoftLayer_SoapClient::getClient('SoftLayer_Virtual_Guest', null, $username, $key);
# Setting the init parameter
$virtualGuestService->setInitParameter($virtualGuestId);
The init parameter is basically the id of the object you wish to get edit or delete, in this case the init parameter is the id of the vulnerability scan you wish to get the report.
You can try this code:
$scanclient = SoftLayer_SoapClient::getClient('SoftLayer_Network_Security_Scanner_Request', '', $apiUsername, $apiKey);
$scanclient->setInitParameter(15326); # The id of the vulnerability scan
$reportstatus = $scanclient->getReport();
To get the list of your vulnerabilities scans in a VSI you can use this method:
http://sldn.softlayer.com/reference/services/SoftLayer_Virtual_Guest/getSecurityScanRequests
and for bare metal servers you can use this one:
http://sldn.softlayer.com/reference/services/SoftLayer_Hardware_Server/getSecurityScanRequests
Regards
I have some Apache Thrift (v.0.6.1) test application with perl-server and php-client.
The behaviour I cannot explain: If we call server-method with invalid argument we see the error in server-output, but php-client stays waiting the response infinitely.
Here are the sources of server:
sub new {
my $classname = shift;
my $self = {};
return bless($self,$classname);
}
sub DateToTimestamp
{
my ($self, $date) = #_;
my $result = CommonAPI::DateToTimestamp($date);
return $result;
}
eval {
my $handler = new RPCHandler;
my $processor = new RPCPerformanceTest::RPCPerformanceTestProcessor($handler);
my $serversocket = new Thrift::ServerSocket(9091);
my $forkingserver = new Thrift::ForkingServer($processor, $serversocket);
print "Starting the server...\n";
$forkingserver->serve();
print "done.\n";
}; if ($#) {
if ($# =~ m/TException/ and exists $#->{message}) {
my $message = $#->{message};
my $code = $#->{code};
my $out = $code . ':' . $message;
die $out;
} else {
die $#;
}
}
and client:
try {
$socket = new TSocket($server_host, $server_port);
$transport = new TBufferedTransport($socket, 1024, 1024);
$protocol = new TBinaryProtocol($transport);
$client = new RPCPerformanceTestClient($protocol);
$transport->open();
$start = microtime(true);
$result = $client->DateToTimestamp('071/26/2011 01:23:45');
var_dump($result);
} catch (Exception $e) {
echo 'Exception: <b>' . $e->getMessage() . '</b>';
}
Why is this happening? Is it my fault? Is it expected behavour?
The Thrift PHP library is a bit broken. You need to manually set the timeouts
E.g.
$socket = new TSocket('host', 9095);
$socket->setSendTimeout(60000);
$socket->setRecvTimeout(60000)
This happens often with protocols that do not supply message length: a client sends more data then the server expects and waits for the server to receive the data. The server receives some of the data, tries to parse it and fails. Now the server-side of the protocol is in errorneous state. If it continues to read the data, it may block. Most probably, the server-side has sent you some error response and is waiting at the same time for the client to receive the response, but that will never happen too.
This is my guess. The best strategy IMHO is to set a time-out for both client and server sockets.
I'm trying to implement a check new mail function to my page.
By this I mean a script that checks the mail, if there exists unread mails it will notify the user "You got one unread mail".
Is this possible?
Thanks in advance
I managed to get it to work as long as the users emails and passwords are stored as plain text in the database.
I'm using a query to retrieve email and password of a user from my database ($email) and ($password)
The code:
$mbox =
imap_open("{imap.domain.com:143/novalidate-cert}INBOX",
"$email", "$password");
The only problem is that the email passwords for my users are stored as md5 hash.
How can I handle this with imap_open?
Thanks
It is possible, if you implement an IMAP (or POP3) client in your PHP script. When you open your page, PHP would connect to the mail server and check for new messages. To achieve this, PHP would need your username/password and server address/port. Hence, this information will have to be stored on the server.
The example given at http://lv.php.net/imap_mailboxmsginfo will give you some more hints.
If you can't use imap_open (the extension is not installed, for example), you can use curl (example tested with gmail):
// https://support.google.com/mail/answer/7126229 [2017-10-22]
define('URL', 'imaps://imap.gmail.com');
define('PORT', 993);
define('USER', 'your.user#gmail.com');
define('PASS', 'your_Secret_Password');
if ($ch = curl_init()) {
curl_setopt($ch, CURLOPT_URL, URL);
curl_setopt($ch, CURLOPT_PORT, PORT);
curl_setopt($ch, CURLOPT_USE_SSL, CURLUSESSL_ALL);
curl_setopt($ch, CURLOPT_USERNAME, USER);
curl_setopt($ch, CURLOPT_PASSWORD, PASS);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HEADER, 0);
// set IMAP command
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'STATUS INBOX (MESSAGES UNSEEN)');
$res = curl_exec($ch);
if (curl_errno($ch)) {
echo 'CURL ERROR: ' . curl_error($ch);
} else {
echo trim($res);
}
echo PHP_EOL;
curl_close($ch);
} else {
die('Curl initialization failed.');
}
The script will return something like:
* STATUS "INBOX" (MESSAGES 2 UNSEEN 1)
More about IMAP commands (https://www.google.com/search?q=imap+protocol+commands) [2017-10-22]:
https://www.rfc-editor.org/rfc/rfc3501
https://donsutherland.org/crib/imap
http://busylog.net/telnet-imap-commands-note/
https://www.skytale.net/blog/archives/23-Manual-IMAP.html
You can comfortably do that using the Zeta Mail component, even without any special extension being available.
$hostname='{imap.gmail.com:993/imap/ssl}INBOX';
$username = 'mygmail#gmail.com';
$password = 'mypass';
$mbox = imap_open($hostname,$username,$password) or die('Cannot connect to Tiriyo: ' . imap_last_error());
$status=imap_status($mbox,$hostname,SA_ALL);
if ($status) {
echo "Messages: " . $status->messages . "<br />\n";
echo "Recent: " . $status->recent . "<br />\n";
echo "Unseen: " . $status->unseen . "<br />\n";
echo "UIDnext: " . $status->uidnext . "<br />\n";
echo "UIDvalidity:" . $status->uidvalidity . "<br />\n";
}
else {
echo "imap_status failed: " . imap_last_error() . "\n";
}
$hostname='{imap.gmail.com:993/imap/ssl}INBOX';
$username = 'mygmail#gmail.com';
$password = 'mypass';
/* try to connect */
$inbox = imap_open($hostname,$username,$password) or die('Cannot connect to Tiriyo: ' . imap_last_error());
$MB = imap_search($inbox,'UNSEEN');
$xcount($MB);
echo $x;