Installing 12 year old php script on Ubuntu

This is a temporary measure.

Old server went away and we needed at least a virtual private server.

Installing MySQL and Apache were a couple of apt-get commands.

This codebase only runs on php5.x, which isn’t supported anymore.

So needed to add this new apt repository which supports legacy php versions.

Found this install solution:

*reference for **PHP 5.6** downgrade from PHP 7

Install add-apt-repository

    sudo apt-get install python-software-properties


Add repository for PHP 5

    sudo add-apt-repository -y ppa:ondrej/php

Update

    sudo apt-get update

Install php5-fpm

    sudo apt-get install php5.6-fpm

Move files

    sudo mv /usr/bin/php /usr/bin/php7
    sudo mv /usr/bin/php5.6 /usr/bin/php

Check PHP version

    php -v

Restart Apache

    sudo service apache2 restart


There were also a few commands in this SO answer that deal with PPA and package install conflicts.

The previous maintainer had suggested that Apt will try to upgrade php, but this may offer a way to prevent that from happening:

dpkg --get-selections | grep ^php5 | sed s/install/hold/g | sudo dpkg --set-selections

Also going to install a working-person’s SSH certificate:
https://www.digitalocean.com/community/tutorials/how-to-secure-apache-with-let-s-encrypt-on-ubuntu-16-04.

This we can only test from a client which routes requests to the domain name to the new IP address. So /etc/hosts file:

44.555.666.78   domain.com
44.555.666.78   www.domain.com

Also need to allow connections on port 443, since we are connecting via https.

Poking around in /etc/apache2/ and searching web. Setting up persistence with iptables settings:

https://www.digitalocean.com/community/tutorials/iptables-essentials-common-firewall-rules-and-commands

This looks like a pretty good route to configuring Apache. Will be pointing to the new certificate from Let’s Encrypt:

/etc/letsencrypt/keys/0000_key-letsencrypt.pem

I think the above was a red herring. May revisit it.

Doesn’t seem to be working. Getting two warnings:

RSA server certificate is a CA certificate (BasicConstraints: CA == TRUE !?)
AH00112: Warning: DocumentRoot [/var/lib/letsencrypt/tls_sni_01_page/] does not exist

Not sure if either are why the pages won’t load under http. Could have to do with fact that server is not at correct domain yet. Have a feeling I simply have Apache configured incorrectly.

I copied two virtual site config files from the former server: apache2/sites-available/ as well as copying the entire apache2 directory and comparing it to mine with the colordif utility, which is a nice little improved version of native diff.

Also had to enable ModReWrite which was enabled in one of the virtual site config files. Under apache2 it’s just a matter of a2enmod rewrite && service apache2 restart. I think you might also have to run service apache2 reload after making config changes.

Liking the output of /etc/init.d/apache2 reload, /etc/init.d/apache2 restart.

Still no handshake. Connection refused on port 443.

Loosely followed tutorial for self-signed certificate.

A new error in trying to curl: Unknown SSL protocol error in connection to domain.com. In the browser we have “An error occurred during a connection to farmdrop.org. SSL received a record that exceeded the maximum permissible length. Error code: SSL_ERROR_RX_RECORD_TOO_LONG”. Thankfully there are apache logs being generated, which there weren’t the first time. Nothing in the error log, though.

Followed troubleshooting guide, added SSLEngine On in sites-available/www.domain.com-le-ssl.conf, within VirtualHost block. New error, now:

SSL certificate problem: Invalid certificate chain

Clear local expired certificates?

Just went back to the certificates copied from the original/current server. Then there were some strange php issues, most of which seemed to have to do with simple coding bugs like <? without the php.

Now setting up phpmail, for the time being using gmail. https://www.digitalocean.com/community/tutorials/how-to-use-gmail-or-yahoo-with-php-mail-function

That didn’t work and I don’t know that we want emails coming from a gmail address. So am going to try setting up postfix:

https://www.digitalocean.com/community/tutorials/how-to-install-and-configure-postfix-as-a-send-only-smtp-server-on-ubuntu-16-04?utm_medium=btb_algo

Getting all these function previously declared errors. Wondering if the functions.php file is getting included multiple times.

Thanks to git version control, i can safely make changes to a bunch of files and easily reset them all if it breaks something with git reset --hard HEAD. So:

find . -type f -exec sed -i 's/include "includes\/functions.php"/require_once("includes\/functions.php")/g' {} +

Hmmm. Still: PHP Fatal error: Cannot redeclare...

Wonder if functions.php is still getting imported multiple times.

Found this code:

grep -rhio ^function\ .*\(  .|awk -F'[( ]'  '{print "echo -n " $2 " && grep -rin " $2 " .|grep -v function|wc -l"}'|bash|grep 0

on SO, of course. Ran this script to confirm the function is only defined once in the functions.php page.

Okay maybe it’s one of the files including functions from a different directory:

find . -type f -exec sed -i 's/include "..\/includes\/functions.php"/require_once("..\/includes\/functions.php")/g' {} +

Hmm. The footer is requiring it this way: include('functions.php');. Maybe that’s a culprit.

find . -type f -exec sed -i 's/include('functions.php');/require_once("functions.php")/g' {} +

Then there are others with include "functions.php".

find . -type f -exec sed -i 's/include "functions.php";/require_once("functions.php")/g' {} +

Finally solved that problem. What’s next in this mess. The functions file is over 6000 lines of code.

Probably a javascript/ajax issue. Throwing an error: throw new Error("my error message"); is js equivalent of php’s die() method. Threw up a basic Ajax test, which is working… at least in Chrome.

Ah. I hadn’t been aware of the short_open_tag parameter in php.ini. The short_open_tags are discouraged, so may replace them all in the codebase. Or just set the parameter to TRUE.

Had to replace retired php functions session_register, session_unregister and session_is_registered to support the codebase:

function session_register($name){
    global $$name;
    $_SESSION[$name] = $$name;
    $$name = &$_SESSION[$name]; 
}
function session_unregister($name){
    unset($_SESSION[$$name]);
}
function session_is_registered($name){
    if(isset($_SESSION[$$name])) return true;
    return false;
}

Install php module to support curl_init. Also thanks SO. Also needed to “uncomment extension=php_curl.dll in php.ini”. And had to see where the curl.so file was:

# find / -type f -name 'curl.so'
/usr/lib/php5/20090626/curl.so

And add that directory to php.ini: extension_dir = "/usr/lib/php5/20090626/".

No. That wasn’t the answer: Failed loading /usr/lib/php5/20090626/xdebug.so: /usr/lib/php5/20090626/xdebug.so: cannot open shared object file: No such file or directory. Where is that file?

# find / -type f -name 'xdebug.so'
/usr/lib/php/20131226/xdebug.so

So we’ll link curl.so to the dir where php seems to be looking for extensions:

ln -s ln -s /usr/lib/php5/20090626/curl.so /usr/lib/php/20131226/

Change php.ini back, re-commenting that extension_dir line. Restart apache2 and…

Wait!

apt install php5.6-curl

Had to specify. Now there’s two version of it:

# find / -type f -name curl.so
/usr/lib/php/20131226/curl.so
/usr/lib/php5/20090626/curl.so

Yay. And php can find curl_init.

Next…

Expression #4 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'table_name' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by.

The code is using dozens of GROUP BY clauses, so simplest solution is to disable only_full_group_by which is enabled by default in newer versions of MySQL. Found a good way here. Login to MySQL as root and SET GLOBAL sql_mode=(SELECT REPLACE(@@sql_mode,'ONLY_FULL_GROUP_BY',''));.

Now it’s logging shop admin in but super slowly. Watching top shows like 90% cpu and 30% memory usage.

Want to/need to bulk update a bunch of $_POST assignments to force type (int, float). Grepping for the $_POST calls wasn’t working. Why? Answer: escaping.

Thank you. grep -r '$_POST\['\''some_form_item'\''\]' . So I can probably update my sed command accordingly. Will try on one file first:

sed -i s/'$_POST\['\''some_form_item'\''\]/(int) $_POST\['\''some_form_item'\''\]'/g some_page.html

Okay. And now:

find . -type f -exec sed -i s/'$_POST\['\''some_form_item'\''\]/(int) $_POST\['\''some_form_item'\''\]'/g {} +

Hey! This again!? this is incompatible with sql_mode=only_full_group_by

mysql> SELECT @@sql_mode;
+-------------------------------------------------------------------------------------------------------------------------------------------+
| @@sql_mode                                                                                                                                |
+-------------------------------------------------------------------------------------------------------------------------------------------+
| ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION |
+-------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

Ran this again:

mysql> SET GLOBAL sql_mode=(SELECT REPLACE(@@sql_mode,'ONLY_FULL_GROUP_BY',''));
Query OK, 0 rows affected (0.00 sec)

Doesn’t look like it did anything. Same output from SELECT @@sql_mode;. Hmmm. Now not getting the error, though. Weird. Fully expect to see it again.

At any rate, let’s start digging into why the order cycle seems to be stopping at PAYPAL.

The word PAYPAL occurs like a million times in a sql file, so how do we exclude a directory from grep?

find . \( -name upgrade -prune \) -o -name "*.php" -exec grep --color -Hn "PAYPAL" {} 2>/dev/null \;

Ah. That’s better. Probably only needed to limit to php files. Dig dig. Poke prod.

grep -ri "\$API_UserName" .

And…

grep -ri "\$txtPaypalUsername" .

Created account and submitted a ticket at https://www.paypal.com/mts.

In the maintime, maybe it’s a SOAP issue. Seems like some of the info in the apache error log like, X-EBAY-SOA-REQUEST-ID have to do with a SOAP API.

php -i | grep -i soap

Nothing. OK.

apt install php-soap

Wait! Let’s make sure it’s the right one for php5.6

apt install php5.6-soap

Now.

php -i | grep -i soap
/etc/php/5.6/cli/conf.d/20-soap.ini,
soap
Soap Client => enabled
Soap Server => enabled
soap.wsdl_cache => 1 => 1
soap.wsdl_cache_dir => /tmp => /tmp
soap.wsdl_cache_enabled => 1 => 1
soap.wsdl_cache_limit => 5 => 5
soap.wsdl_cache_ttl => 86400 => 86400

Okay! Still not working, though. Let’s look into this file:

/shop/parallel_pay_success.php?usertype=user

Tracked down another error, just by printing out sql queries and trying them in the command line:

ERROR 1364 (HY000): Field 'vgiftcertificate_code' doesn't have a default value

Ah. Solution may be in STRICT_TRANS_TABLES.

mysql> SET GLOBAL sql_mode=(SELECT REPLACE(@@sql_mode,'STRICT_TRANS_TABLES',''));

Hmmm. These setting aren’t sticking. Restart MySQL: /etc/init.d/mysql restart.

Couple of little changes in /etc/mysql/mysql.cnf:

# The MySQL database server configuration file.
#
# You can copy this to one of:
# - "/etc/mysql/my.cnf" to set global options,
# - "~/.my.cnf" to set user-specific options.
# 
# One can use all long options that the program supports.
# Run program with --help to get a list of available options and with
# --print-defaults to see which it would actually understand and use.
#
# For explanations see
# http://dev.mysql.com/doc/mysql/en/server-system-variables.html

#
# * IMPORTANT: Additional settings that can override those from this file!
#   The files must end with '.cnf', otherwise they'll be ignored.
#

!includedir /etc/mysql/conf.d/
!includedir /etc/mysql/mysql.conf.d/
[mysqld]
sql_mode = "NO_ENGINE_SUBSTITUTION,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER"

Seem to be rocking again.