It was my first time to see a hacker is close to me.
I was flooded with notification emails from Google Adsense subjected “Your AdSense Publisher Policy Violation Report” from yesterday afternoon. I immediately tried to visit either blog.goods-pro.com or goods-pro.com to see what was going on. I got a scary warning message saying either site contains malware by Chrome and Firefox (on desktop. Chrome for Android does not do safe browsing check. I don’t know if Firefox does so.)
It took me a while to find out which site contains malware. As blog.goods-pro.com was using AdSense but goods-pro.com wasn’t, at first I thought it was blog.goods-pro.com that were hacked. blog.goods-pro.com was powered by WordPress, so I went through all the plugins and compared with my other WordPress sites, I didn’t find a suspicious plugin.
Then I started to look into the main domain site goods-pro.com, which was installed with Magento. It took me quite a while for me to know there was a good tool from https://sitecheck.sucuri.net/ to check what malware was on the site.
Then it took me another while to find out how the hacker did it. Basically the hacker compromised one of admin’s (not mine) password, and add the following code in three places (design/footer/copyright, design/head/includes, design/footer/absolute_footer) in Magento System >> Configuration.
hersosx2sk.tk and mytokeasn2s.ru are malware sites. And if a site links to them, it is regarded as malware site as well.
When I disabled access of compromised admin accounts (without removing the injected code), I found Chrome and Firefox stopped giving that scary warnings, and visits to hersosx2sk.tk or mytokeasn2s.ru are redirected to Google. I don’t understand how Google can take control of these domains so quick, but anyway, it is not my business.
At last I removed all malware codes and requested AdSense a review of blog.goods-pro.com.
I changed a server for Magento sites. When I migrated the sites, they looked fine. However after I flushed Magento image cache, all sites stopped working. Web pages were not completed. The code stopped rendering after the first product image’s “src”. But there was no error message afterwards.
At first I thought it was file permission problem. But it was not.
Then I thought it was some rubbish left over after flushing cache. So I took the advice by removing the folder media/catalog/product/cache and clearing everything under var. But the problem was still there.
Then I realised it was php not generating images for Magento. Magento requires php-gd to generate images. My new server did not have php-gd installed. If I was installing a Magento instance, I would not get through. But I migrated the sites. So they “looked” fine.
After installed php-gd, product images came back.
By the way, Magento requires some other PHP extensions to run. I took the chance to install them all.
Although I released a Magento module “Root Category as Homepage“, which enables replacing the default CMS page with the root category as homepage, thus the users can start layered navigation from the very top level of category, the usage of this module should be limited, for the sake of usability.
In short, use Magento layered navigation only to narrow down the choice of products. Do not use it for the purpose of grouping products by some filter attributes. There are many other ways to group products together.
I will explain in details when I have some more time.
Today a Magento store owner asked me why he could not create a new attribute set based on an existing one. I took a look into his store and found out the existing attribute set has many custom attributes, which led to new attribute set creation would take more than 30 seconds. But 30 seconds is the default PHP max execution time, which is set in php.ini and has not been optimised for Magento backend operation.
My immediate reaction was changing the default value of max_execution_time to 120. I added a line in /etc/php-fpm.d/www.conf, where is my preferential place to set server wide PHP directives rather than /etc/php.ini.
php_admin_value[max_execution_time] = 120
After a while, I had another thought. I do not like to extend PHP max execution time for most of other websites on the same server. Even for the Magento store, longer execution time is only needed for the backend operations. So how can I specify different PHP directives for different websites? Particularly, how can I specify longer execution time or larger memory limit for Magento admin users?
My first idea was creating separate php-fpm (Yes, I am using php-fpm.) profiles for this purpose. However, I rejected this idea after 2 seconds, because:
I do not like to create more PHP daemons into the valuable server memory.
If Magento frontend and backend are on the same domain, I have no way to assign a corresponding daemon.
So, can I implement changing run-time PHP directives using a Magento module? Of course. I had a Magento module called Msdk (Magento SDK). I just need to add this feature to Msdk.
Firstly, I need to find a proper event to catch. The event should be dispatched only once per request, and earliest possible when it can distinguish frontend or adminhtml route. The earliest event is “controller_front_init_before” except some database events, which are not recommend to catch anyway. But “controller_front_init_before” can not distinguish frontend or adminhtml route, i.e. it can only be put into global section in config.xml. Following the event timeline, I find “frontend or adminhtml route” is the best event to catch.
Secondly, I put one “controller_front_init_before” event catching into frontend section and another into adminhtml section in config.xml of Msdk module.
Thirdly, write two observers in a Helper or a Model to apply PHP directives.
Lastly, modify system.xml to allow users to set PHP directives in Magento System Configuration.
It sounds complicated but actually not. I finished it in a couple of hours.
BTW, Msdk is one of my free modules. But I am not going to launch it now with only one new feature. Watch the space for updated news.