<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>MV Associati Tech Gems &#187; DevOps</title>
	<atom:link href="http://www.mvassociati.it/en/gems/devops/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.mvassociati.it/en/gems</link>
	<description>Technical Article from MV Associati experience</description>
	<lastBuildDate>Fri, 04 Aug 2017 10:31:17 +0000</lastBuildDate>
	<language>en-EN</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.4.2</generator>
		<item>
		<title>Securing intranet applications with SSL</title>
		<link>http://www.mvassociati.it/en/gems/devops/https-on-private-intranet-applications-ssl-certificate?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=securing-intranet-applications-with-https</link>
		<comments>http://www.mvassociati.it/en/gems/devops/https-on-private-intranet-applications-ssl-certificate#comments</comments>
		<pubDate>Mon, 08 May 2017 07:02:39 +0000</pubDate>
		<dc:creator>whites11</dc:creator>
				<category><![CDATA[DevOps]]></category>
		<category><![CDATA[https]]></category>
		<category><![CDATA[intranet]]></category>
		<category><![CDATA[letsencrypt]]></category>
		<category><![CDATA[security]]></category>
		<category><![CDATA[ssl]]></category>

		<guid isPermaLink="false">http://www.mvassociati.it/en/gems/?p=848</guid>
		<description><![CDATA[We all know how important is HTTPS for securing data flowing between users&#8217; web browsers and the webserver. With the release of Chrome 56, Google decided to start marking websites not served using the HTTPS protocol as Insecure (source), so it is becoming even more important, if not critical, to use HTTPS for all web [...]]]></description>
			<content:encoded><![CDATA[<p>We all know how important is <strong>HTTPS</strong> for securing data flowing between users&#8217; web browsers and the webserver.<br />
With the release of Chrome 56, <strong>Google</strong> decided to start marking websites not served using the HTTPS protocol as <strong>Insecure</strong> (<a title="source" href="https://www.wordfence.com/blog/2017/01/chrome-56-ssl-https-wordpress/" target="_blank">source</a>), so it is becoming even more important, if not critical, to use HTTPS for all web applications.</p>
<p>This is obviously relevant for web applications and websites in general, which are available to the public. In such situations, the typical solution is to purchase an <strong>SSL certificate</strong> from a certification authority (such as RapidSSL or GoDaddy) and enable it within the webserver. This article is not about this.  </p>
<p>What we&#8217;re going to talk about today is the <strong>security of Intranet web applications</strong>, such as a websites which are not publicly available, but somehow available to specific people having access to private networks.<br />
<span id="more-848"></span></p>
<h4></h4>
<h4><strong>Why is it important to secure intranet applications too?</strong></h4>
<p>Somebody might think that, since an application is not publicly available, it is not important to secure it with SSL. This is not true, and here&#8217;s why.</p>
<p>Think about a document storage web application that is running in the local area network (LAN) of your company. That application of course may contain many documents of different nature, such as customers&#8217; and suppliers&#8217; invoices and employees contracts and payment receipts.<br />
While some of this documents might be visible to all the users of such web application, many others have to be visible to specific users only.<br />
Let&#8217;s say that you implement a very secure ACL to ensure this security layer on your application and avoid unauthorized access to your sensitive data.<br />
If you don&#8217;t serve your project using the HTTPS protocol, than all your documents are traveling in the cables of your LAN unencrypted, and anybody connected to the same network can easily scan your network and read those documents. Plus, a malicious user could use the same technique to sniff user passwords and easily access your secure web app with other peoples&#8217; credentials (don&#8217;t you believe that? Check this <a title="tutorial" href="http://lifehacker.com/5853483/a-guide-to-sniffing-out-passwords-and-cookies-and-how-to-protect-yourself-against-it" target="_blank">tutorial</a>).</p>
<p></p>
<p>That said, I hope you are all convinced now that SSL is important for every web application, even if it&#8217;s not public.</p>
<p>&nbsp;</p>
<h4><strong>How to secure an intranet application</strong></h4>
<p>There are a few options to secure private web applications.</p>
<ol>
<li>The dumbest option is to generate a self signed certificate. That does not solve the security problem though (read <a title="this link" href="https://www.globalsign.com/en/ssl-information-center/dangers-self-signed-certificates/" target="_blank">this</a> to understand why).</li>
<li>Buy a standard certificate. This is perfectly acceptable but requires spending some amount of money every year.</li>
<li>Generate a certificate using <a href="https://letsencrypt.org/" target="_lets">Letsencrypt</a></li>
</ol>
<p></p>
<p>If you haven&#8217;t heard about <strong>Letsencrypt</strong> before, go have a look at their <a href="https://letsencrypt.org/about/" target="_blank">website</a> to learn more. In one sentence, it is an organization that aims at making the web more secure and gives you free SSL certificates for personal or professional use.<br />
This is in my opinion the perfect solution for intranet applications (which tipically have budget constraints).</p>
<p>&nbsp;</p>
<h4><strong>Generating SSL certificates with letsencrypt</strong></h4>
<p>Letsencrypt uses the <a href="https://en.wikipedia.org/wiki/Automated_Certificate_Management_Environment" target="_blank"><strong>ACME</strong></a> protocol to release SSL certificates in an automated manner.</p>
<p>That means you need an ACME client to get an SSL certificate. The official client is called <a href="https://certbot.eff.org/" target="_blank">certbot</a>, it&#8217;s free and open source and it is easily installable in many UNIX-based operating systems. We&#8217;re not going to cover the installation of certbot, though, because it is out of scope. You can find easy tutorials for your operating system on the <a href="https://certbot.eff.org/" target="_blank">officiale page</a>.</p>
<p>There are a few different ways to get a new certificate using certbot (such as apache, nginx, webroot, and so on. Read them <a href="https://certbot.eff.org/docs/using.html#getting-certificates-and-choosing-plugins" target="_blank">here</a>) but all of them have a very important common step to be performed which is domain ownership verification. This step is required by the certification authority to ensure that you are the owner, or at least you are allowed to manage, the DNS records for the internet domain you are requiring the certificate for. Skipping this step would mean that anybody could request a certificate for <em>google.com</em> or <em>paypal.com</em> and that of course would be a giant security problem.</p>
<p>&nbsp;</p>
<h4><strong>How does Letsencrypt check domain ownership?</strong></h4>
<p>There are basically 2 ways:</p>
<ul>
<li>HTTP challenge: an HTTP request is sent to the domain name you requested the domain for. The server must respond to a specific endpoint with a specific content in order for the domain ownership to be verified.</li>
<li>DNS challenge: letsencrypt servers will search on the DNS records of the requested domain for a specific TXT record, with a specific value.</li>
</ul>
<p>HTTP challenge is the most common and the easiest, because certbot (and other ACME clients) can do that for you automatically. Unluckily, it requires that the domain name resolves to a public IP address which is freely reachable on the internet. But, remember, our domain is in the intranet and so this approach simply would not work in our scenario. That means we need to choose the DNS challenge option.</p>
<p>&nbsp;</p>
<h4><strong>Generate a certificate using the DNS challenge</strong></h4>
<p>To do that, we need to use the <em>manual</em> strategy of certbot, by running a command similar to the following:</p><pre class="crayon-plain-tag">certbot -d private.mydomain.com --manual --preferred-challenges dns certonly</pre><p>Of course adjust <em>private.mydomain.com</em> with your domain.<br />
This command starts an interactive wizard:</p><pre class="crayon-plain-tag">Saving debug log to /var/log/letsencrypt/letsencrypt.log
Obtaining a new certificate
Performing the following challenges: dns-01 challenge for private.mydomain.com
------------------------------------------------------------------
NOTE: The IP of this machine will be publicly logged as having requested this certificate. If you're running certbot in manual mode on a machine that is not your server, please ensure you're okay with that.
Are you OK with your IP being logged?
------------------------------------------------------------------
(Y)es/(N)o: Y

------------------------------------------------------------------
Please deploy a DNS TXT record under the name _acme-challenge.private.mydomain.com with the following value:

LngHg_3lhXDJ_m3ArGTgtalz50uVCjXW5-zFVCulK8I

Once this is deployed,
------------------------------------------------------------------
Press Enter to Continue</pre><p>At this point, as clearly requested by the script, you need to create a new TXT record in your DNS administration panel for <em>_acme-challenge.private.mydomain.com</em> with value <em>LngHg_3lhXDJ_m3ArGTgtalz50uVCjXW5-zFVCulK8I</em></p>
<p>Once done, check that the DNS record propagated successfully (you can use <a href="https://www.whatsmydns.net/" target="_blank">this website</a> to do that) than press enter to continue executing the script.</p>
<p>If all went well, you should see a success message:</p><pre class="crayon-plain-tag">IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at /etc/letsencrypt/live/private.mydomain.com/fullchain.pem.
Your cert will expire on 2017-05-16. To obtain a new or tweaked version of this certificate in the future, simply run certbot again.
To non-interactively renew *all* of your certificates, run &quot;certbot renew&quot;
- If you like Certbot, please consider supporting our work by:
Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
Donating to EFF: https://eff.org/donate-le</pre><p>Good, our certificates are ready! You can find everything you need under the folder: /etc/letsencrypt/live/mydomain.com/ (of course adjust the path to meet your domain name). In that folder you&#8217;ll find 4 files:</p>
<ul>
<li>cert.pem: the actual certificate</li>
<li>chain.pem: the certificate of the certification authority</li>
<li>fullchain.pem: basically the merge of the above 2 files</li>
<li>privkey.pem: your private key (never share this file with anybody)</li>
</ul>
<p>Now you only have to tell your webserver to use the HTTPS protocol and where to get the certificate files. Check the official documentation for <a href="http://nginx.org/en/docs/http/configuring_https_servers.html" target="_blank">Nginx</a> and <a href="https://httpd.apache.org/docs/2.4/ssl/ssl_howto.html" target="_blank">apache</a> to get started.</p>
<p></p>
<h4><strong>Recap</strong></h4>
<p>In this article we discussed about the risks of having a plain HTTP web application hosted inside our company’s private network and the need of an SSL certificate to make traffic flow securely inside our ethernet wires.</p>
<p>We then learned how to generate a free SSL certificate using Letsencrypt even if our webservers are not public.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mvassociati.it/en/gems/devops/https-on-private-intranet-applications-ssl-certificate/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Docker, PHP and E-Mail: getting things to work</title>
		<link>http://www.mvassociati.it/en/gems/devops/docker-email-php?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=docker-php-and-e-mail-getting-things-to-work</link>
		<comments>http://www.mvassociati.it/en/gems/devops/docker-email-php#comments</comments>
		<pubDate>Fri, 10 Feb 2017 16:21:16 +0000</pubDate>
		<dc:creator>whites11</dc:creator>
				<category><![CDATA[DevOps]]></category>
		<category><![CDATA[devops]]></category>
		<category><![CDATA[docker]]></category>
		<category><![CDATA[email]]></category>
		<category><![CDATA[mailhog]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[sendmail]]></category>
		<category><![CDATA[ssmtp]]></category>

		<guid isPermaLink="false">http://www.mvassociati.it/en/gems/?p=668</guid>
		<description><![CDATA[It&#8217;s a common need for software nowadays to send notifications through e-mail: registration confirmations, password recovery requests, event notifications and so on. As my colleagues develop software, they often encounter problems while dealing with such e-mail exchange in their local (Docker) environment. The problem Let&#8217;s say you are also developing a PHP application and you [...]]]></description>
			<content:encoded><![CDATA[<p>It&#8217;s a common need for software nowadays to send notifications through <strong>e-mail</strong>: registration confirmations, password recovery requests, event notifications and so on. As my colleagues develop software, they often encounter problems while dealing with such e-mail exchange in their local (Docker) environment.<span id="more-668"></span></p>
<h2>The problem</h2>
<p>Let&#8217;s say you are also developing a <strong>PHP</strong> application and you want to use <strong>docker</strong> in your development machine. You will notice that &#8211; if you use the official PHP images from the docker hub &#8211; sending e-mail out of the box simply won&#8217;t work. Lets&#8217; see what I mean in practice, considering this simple index.php file, sending out an e-mail:</p><pre class="crayon-plain-tag">$result = mail(&quot;info@example.com&quot;, &quot;Subject&quot;, &quot;The very important email body&quot;);

if ($result) {
    echo &quot;Email sent correctly&quot;;
} else {
    echo &quot;Error sending the email&quot;;
}</pre><p><em>Please note: using the mail command to send an email is the simplest way, but there are many more powerful libraries out there that could make things easier. We have chosen to use the mail command just to keep the example as simple as possible.</em></p>
<p>If we run it using docker with the following command:</p><pre class="crayon-plain-tag">docker run -p &quot;80:80&quot; -v `pwd`:/var/www/html --rm php:7-apache</pre><p>and visit http://localhost with our browser, we&#8217;ll see that the mail command will fail, and we&#8217;ll get an &#8220;Error sending the email&#8221; message.</p>
<p>The reason why this happens is that the &#8220;mail&#8221; command relies on the &#8220;sendmail&#8221; system command inside the container, which is missing from the official PHP docker image.</p>
<p><a href="http://www.mvassociati.it/en/gems/wp-content/uploads/2017/02/docker-email.png" rel="lightbox[668]" title="docker-email"></a></p>
<p>While you could simply create a new image extending the original one and adding the sendmail command, I suggest using a different strategy.</p>
<p>Here at MV Labs we do use a tool called <strong>Mailhog</strong> (<a title="MailHog" href="https://github.com/mailhog/MailHog" target="_blank">https://github.com/mailhog/MailHog</a>) which acts as an SMTP server listening on port 1025 but instead of sending real emails to your recipients, it simply displays them in a handy web interface (which is listening, by default, on port 8025). This way you avoid the risk of sending your testing e-mails to the customer (it happened at least once to everybody) and you don&#8217;t have to deal with spam filters or other annoyances in the e-mail chain.</p>
<p>So, how can we achieve this? To make things easier, we can take advantage of docker-compose. Let&#8217;s start by adding the mailhog container to our services:</p><pre class="crayon-plain-tag">version: '2'
services:
  php:
    image: php:7-apache
    volumes:
      - .:/var/www/html/
    ports:
      - 80:80
    networks:
      - base
  mailhog:
    image: mailhog/mailhog
    ports:
      - 8025:8025
    networks:
      - base
networks:
  base:</pre><p>Now, if we run <code>docker-compose up</code> and head our browsers to http://localhost:8025 we should see the mailhog simple but powerful web interface.</p>
<p>We&#8217;re not done yet, though, as we still need to tell the mail command to send emails through our new mailhog smtp server. Unluckily this requires the building of a custom docker image, since PHP doesn&#8217;t allow using the native mail command to connect to a SMTP server. For this reason, we need a tool called <strong>ssmtp</strong> (<a title="ssmtp" href="https://linux.die.net/man/8/ssmtp" target="_blank">https://linux.die.net/man/8/ssmtp</a>) which is basically a configurable sendmail command replacement, and which forwards the message to a SMTP server configured in its config file. We&#8217;ll need the following Dockerfile:</p><pre class="crayon-plain-tag">FROM php:7-apache

# install ssmtp
RUN apt-get update; apt-get install ssmtp -y

# tell php to use ssmtp's sendmail for email sending
RUN echo &quot;sendmail_path=/usr/sbin/sendmail -t -i&quot; &amp;gt;/usr/local/etc/php/conf.d/sendmail.ini

# tell ssmtp to use mailhog as the mail transport
RUN echo &quot;Mailhub=mailhog:1025&quot; &amp;gt; /etc/ssmtp/ssmtp.conf
RUN echo &quot;FromLineOverride=Yes&quot; &amp;gt;&amp;gt; /etc/ssmtp/ssmtp.conf</pre><p>Then we&#8217;ll need to tell docker-compose.yml to build the image from the Dockerfile for our PHP container:</p><pre class="crayon-plain-tag">version: '2'
services:
  php:
    build: .
    volumes:
      - .:/var/www/html/
    ports:
      - 80:80
    networks:
      - base
  mailhog:
    image: mailhog/mailhog
    ports:
      - 8025:8025
    networks:
      - base
networks:
  base:</pre><p>and build our containers again with:</p><pre class="crayon-plain-tag">docker-compose up -d --build</pre><p>Now we&#8217;re ready to send our first &#8220;virtual&#8221; email. Just head your browser to http://localhost and you&#8217;ll get the message &#8220;Email sent correctly&#8221;. If you check your mailhog at http://localhost:8025 you&#8217;ll see your email!</p>
<h2>Summary</h2>
<p>Using a simple example, we have demonstrated one possible solution for sending test e-mails out of our web applications under development in a secure and handy way, by using some nice open source tools such as SSmtp and Mailhog inside a docker dev environment.</p>
<p>Let us know what you think in the comments area below and happy developing!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mvassociati.it/en/gems/devops/docker-email-php/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PHP error: file size limit exceeded</title>
		<link>http://www.mvassociati.it/en/gems/devops/php-error-file-size-limit-exceeded/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=php-error-file-size-limit-exceeded</link>
		<comments>http://www.mvassociati.it/en/gems/devops/php-error-file-size-limit-exceeded/#comments</comments>
		<pubDate>Fri, 04 Jan 2013 14:12:26 +0000</pubDate>
		<dc:creator>maraspin</dc:creator>
				<category><![CDATA[DevOps]]></category>
		<category><![CDATA[file size]]></category>
		<category><![CDATA[include]]></category>
		<category><![CDATA[issue]]></category>
		<category><![CDATA[logging]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[php.ini]]></category>
		<category><![CDATA[settings]]></category>
		<category><![CDATA[timezone]]></category>

		<guid isPermaLink="false">http://www.mvassociati.it/en/gems/?p=454</guid>
		<description><![CDATA[Troubleshooting PHP interpreter issues can be tricky. A few days ago a client reported that one of his cron job scripts wasn&#8217;t being executed on his x86_64 CentOS 5.8 server, running Zend Server CE PHP 5.3.14. Troubleshooting such situations is usually straightforward, but this time PHP error messages I got were so ambiguous, and issues [...]]]></description>
			<content:encoded><![CDATA[<p>Troubleshooting PHP interpreter issues can be tricky. A few days ago a client reported that one of his cron job scripts wasn&#8217;t being executed on his x86_64 CentOS 5.8 server, running Zend Server CE PHP 5.3.14. Troubleshooting such situations is usually straightforward, but this time PHP error messages I got were so ambiguous, and issues were so many at the same time, that I decided to write a blog post, hoping that it can be of some help for someone else.<span id="more-454"></span></p>
<h3>The Problem</h3>
<p>Script wasn&#8217;t outputting nor logging anything, so in order to find out more about the problem, I thought about logging last script execution datetime myself. I wanted to find out whether the problem was related to cron execution, or rather to some issue within the script itself. So I added following two lines (on top to the script):</p><pre class="crayon-plain-tag">$s_content = 'Script last run: '. date(&quot;d/m/Y h:i:s&quot; . &quot;\n&quot;);
file_put_contents('/tmp/cert_import.log', $s_content);</pre><p>And executed it:</p><pre class="crayon-plain-tag">php ./importa_certificati.php</pre><p>All I got was a nasty error message:</p><pre class="crayon-plain-tag">File size limit exceeded</pre><p>At first I thought the problem might&#8217;ve been related to the specific file name I had picked (IE /tmp/cert_import.log). Did it exist already and was it already too big? I was sure I had checked things out. And actually, file wasn&#8217;t there upon a second check. So what was PHP ranting about? Could have it been a permission issue? Nope, script was being executed by root and was executable. So, where did the problem lie? I started to search for the problem by reverting the script to its original form, commenting out my additions:</p><pre class="crayon-plain-tag">// $s_content = 'Script last run: '. date(&quot;d/m/Y h:i:s&quot; . &quot;\n&quot;);
// file_put_contents('/tmp/cert_import.log', $s_content);</pre><p>Problem magically disappeared. Weird, I thought. &#8220;Let&#8217;s see what happens if I prepare my string, but don&#8217;t it write to the file, I said to myself. I&#8217;m sure the problem lies there. Let&#8217;s check&#8221;:</p><pre class="crayon-plain-tag">$s_content = 'Script last run: '. date(&quot;d/m/Y h:i:s&quot; . &quot;\n&quot;);
// file_put_contents('/tmp/cert_import.log', $s_content);</pre><p></p><pre class="crayon-plain-tag">File size limit exceeded</pre><p>Whaat?!? Problem still there, despite no attempt to write to a file is even made. Things start to look awkward.</p>
<h3>The Cause</h3>
<p>What I had just discovered was that problem didn&#8217;t have anything to do with the file I was trying to write, but was related instead to the PHP process itself. In fact, wondering what other file size limit might&#8217;ve been reached, I came to think about logging. So, I opened php.ini and checked things out. Logging was configured indeed, pointing at /usr/local/zend/var/log/php.log through following directives:</p><pre class="crayon-plain-tag">; http://php.net/log-errors
log_errors = On

; Set maximum length of log_errors. [...]
log_errors_max_len = 1024

; Log errors to specified file. PHPs default behavior is to leave this value
; empty.
error_log = &quot;/usr/local/zend/var/log/php.log&quot;</pre><p>I changed my working directory to /usr/local/zend/var/log/ and checked things out with ls:</p><pre class="crayon-plain-tag">[root@XXX ~]# cd /usr/local/zend/var/log/
[root@XXX log]# ls -alh
-rw-rw---- 1 apache zend 2.0G Dec 27 17:30 php.log</pre><p>That exact 2Gb size looked suspicious, to say the least. Especially because the php.ini log_errors_max_len directive above had a 1024 value, not a 2048 one. So, I moved the log file out of its way, and gzipped it (so to save some space, without losing anything).</p><pre class="crayon-plain-tag">mv php.log
gzip php.log</pre><p>I then run the script again. All went well this time, with no error being reported. Problem was caused by log file size indeed. Most likely no one cared about rotating it, believing that log_errors_max_len would do the job. As it&#8217;s explained on <a title="PHP log_errors_max_len" href="http://stackoverflow.com/questions/1966540/log-errors-max-len-1024-in-php-ini-but-php-log-keeps-growing">stackoverflow</a> though, despite its possibly ambiguous name, log_errors_max_len only deals with the size of a single log message, not with the size of the log file itself.</p>
<p></p>
<p>Newly introduced problem was solved. But I was still wondering what might&#8217;ve caused the problem from the lines I had added in first place. Luckily I now had logs to check.</p>
<h3>The timezone not set and include underlying issues</h3>
<p>I opened the new php.log file and found a few entries like the following:</p><pre class="crayon-plain-tag">[05-Dec-2012 23:00:04 UTC] PHP Warning:  strtotime(): It is not safe to rely on the system's timezone settings. 
You are *required* to use the date.timezone setting or the date_default_timezone_set() function. 
In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. 
We selected 'Europe/Berlin' for 'CET/1.0/no DST' instead in /[...]/importa_certificati.php on line 14</pre><p>Easy problem to fix. And also found the reason why log file filled up so quickly. Such message was written for every run of another script where the date function was used.</p>
<p></p>
<p>Still, I hadn&#8217;t solved my problem yet. Script would run from console, but wouldn&#8217;t from cron. Again, logs proved to be my friends, with entries like the following:</p><pre class="crayon-plain-tag">[27-Dec-2012 23:09:02 UTC] PHP Warning:  include_once(../classi/dbconnect.php): failed to open stream: No such file or directory in /[...]/importa_certificati.php on line 3
[27-Dec-2012 23:09:02 UTC] PHP Warning:  include_once(): Failed opening '../classi/dbconnect.php' for inclusion (include_path='.:/[...]') in /[...]/importa_certificati.php on line 3
[27-Dec-2012 23:09:02 UTC] PHP Warning:  include_once(../classi/utils.php): failed to open stream: No such file or directory in /[...]/importa_certificati.php on line 4
[27-Dec-2012 23:09:02 UTC] PHP Warning:  include_once(): Failed opening '../classi/utils.php' for inclusion (include_path='.:[...]') in /[...]/importa_certificati.php on line 4
[27-Dec-2012 23:09:02 UTC] PHP Fatal error:  Class 'utils' not found in /[...]/importa_certificati.php on line 10</pre><p>I had just found out that problem was due to the script having relative includes in the following form:</p><pre class="crayon-plain-tag">&lt;!--?php

include_once('../classes/dbconnect.php');
include_once('../classes/utils.php');

$s_pathCerts = __DIR__ . '/../rsync/data';

&lt;/pre--&gt;</pre><p>So everything worked when the script was tested by customer from local directory:</p><pre class="crayon-plain-tag">php ./importa_certificati.php</pre><p>But once it was invoked by cron, it stopped working, since path wasn&#8217;t quite the same.<br />
And, because no error messages related to the issue were collected in php.log, no one ever discovered about the problem with the script, and blamed cron settings instead.<br />
Changing lines above tothe following solved the problem:</p><pre class="crayon-plain-tag">&lt;!--?php

include_once(__DIR__ . '/../classes/dbconnect.php');
include_once(__DIR__ . '/../classes/utils.php');

$s_pathCerts = __DIR__ . '/../rsync/data';

&lt;/pre--&gt;</pre><p>&nbsp;</p>
<h3>Things to take home from this experience</h3>
<ol>
<li>If php can not write to its log file it will stop script execution, without giving a clear explanation of what&#8217;s going on</li>
<li>The log_errors_max_len directive is a bit ambiguous. It deals with each log record, not with the whole file size</li>
<li>You always need to set your timezone, if you don&#8217;t want to have your logs filled with crap</li>
<li>When including stuff, it&#8217;s wise to rely on the php __DIR__ or dirname(__FILE__) constructs rather than on relative paths. You can&#8217;t be sure the scritpt will be invoked from where you expect.</li>
<li>When troubleshooting it&#8217;s important to think &#8220;outside&#8221; the box. In this case the problem was related to the script itself, as much as it was related to its environment.</li>
<li>If you do write to logs, you need to check&#8217;em out every once in a while. Having their content e-mailed to you periodically is also a good idea</li>
</ol>
<p>Elephant picture courtesy of http://www.flickr.com/photos/laughingsquid/2218075860/</p>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mvassociati.it/en/gems/devops/php-error-file-size-limit-exceeded/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
