If you can’t access network from php script running under Apache (e.g. fetch network resource with file_get_contents, cUrl, SoapClient, etc …), there are at least three problems that needs to be checked and fixed.
- php.ini settings
- SELinux settings
- Apache and network service dependencie problem
Test script:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<?php $str = file_get_contents('http://drib.tech'); if($str === false) { print_r(error_get_last()); die(__FILE__ . __LINE__); } echo htmlspecialchars($str); ?> |
php.ini settings
If test script outputs something like this:
1 |
file_get_contents(http://drib.tech): failed to open stream: no suitable wrapper could be found |
check current setting of the allow_url_fopen and the correct location of the php.ini .
phpinfo() output:
1 2 3 |
<?php phpinfo(); ?> |
Result:
Check for allow_url_fopen:
Set it to On:
1 |
$ sudo vim /etc/php.ini |
Find allow_url_fopen in php.ini file and set it to On:
1 2 3 4 5 6 7 |
;;;;;;;;;;;;;;;;;; ; Fopen wrappers ; ;;;;;;;;;;;;;;;;;; ; Whether to allow the treatment of URLs (like http:// or ftp://) as files. ; http://php.net/allow-url-fopen allow_url_fopen = On |
Note: Leave allow_url_include set to Off.
Restart apache server
CentOS:
1 |
$ sudo service httpd restart |
Ubuntu:
1 |
$ sudo restart httpd |
Check to see if the problem is fixed.
SELinux settings
SELinux stands for Security Enhanced Linux is implementation of MAC (Mandatory Access Control) mechanism which gives one more layer of security after the standard DAC (Discretionary Access Control). By default network connection from httpd (Apache) is disabled. To learn more about SELinux check Red Hat documentation.
First check is SELinux enabled:
1 |
$ sudo sestatus |
If enabled, you should get something like this:
1 2 3 4 5 6 7 8 9 |
SELinux status: enabled SELinuxfs mount: /sys/fs/selinux SELinux root directory: /etc/selinux Loaded policy name: targeted Current mode: enforcing Mode from config file: enforcing Policy MLS status: enabled Policy deny_unknown status: allowed Max kernel policy version: 28 |
Probably script will not output any errors. Apache error log will not be updated neither. Check SELinux log file:
$ sudo less /var/log/audit/audit.log
For errors like this:
1 |
type=AVC msg=audit(1502720146.620:1789) : avc: denied { name_connect } for pid=5245 comm="httpd" dest=30136 scontext=system_u:system_r: httpd_t:s0 tcontext=system_u:object_r: unreserved_port_t:s0 tclass=tcp_socket |
Please note httpd and denied. π
Check those SELinux boolean flags: httpd_can_network_connect, httpd_unified :
1 2 3 4 |
$ sudo sestatus -b | grep httpd_can_network_connect httpd_can_network_connect off httpd_can_network_connect_cobbler off httpd_can_network_connect_db off |
1 2 |
$ sudo sestatus -b | grep httpd_unified httpd_unified on |
If off, set it to on. Execute:
1 |
$ sudo setsebool -P httpd_can_network_connect 1 |
1 |
$ sudo setsebool -P httpd_unified 1 |
Flag -P makes the new setting permanent.
To be sure, reboot.
Apache and network service dependencies problem
If test script is still not working and giving error like this:
1 |
file_get_contents(http://drib.tech): failed to open stream: php_network_getaddresses: getaddrinfo failed: Name or service not known |
Try restarting Apache.
CentOS:
1 |
$ sudo service httpd restart |
Ubuntu:
1 |
$ sudo restart httpd |
If the script is now working – you haveΒ Apache and network service dependencies problem. When the systems boots processes are started asynchronous and Apache is started before network service is fully up and running. NSSΒ lookup (Name Server Switch which also includes DNS – Domain Name Server lookup) is fully configured after the Apache has started – so Apache doesn’t know how to resolve the domain. This is why it works after Apache is restarted manually. Follow this steps to correctly configure services dependencies.
Execute:
1 |
$ sudo systemctl enable NetworkManager-wait-online |
Edit config files to make sure that Apache is started after the network services and also after the MySQL – because when I need Apache I also need to have MySQL up and running.
Edit mysqld.service:
1 |
$ sudo vim /lib/systemd/system/mysqld.service |
Change Requires and After to:
1 2 |
Requires=network.target After=network.target nss-lookup.target syslog.target network-online.target |
Edit httpd.service:
1 |
$ sudo vim /lib/systemd/system/httpd.service |
Change Requires and After to:
1 2 |
Requires=mysqld.service After=network.target remote-fs.target nss-lookup.target mysqld.service network-online.target |
Execute:
1 |
$ sudo systemctl daemon-reload |
And reboot to test.
After reboot execute:
1 |
$ systemd-analyze critical-chain |
To see service execution chain:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
graphical.target @16.063s ββmulti-user.target @16.063s ββhttpd.service @10.301s +189ms ββmysqld.service @8.742s +1.554s ββnetwork-online.target @8.739s ββnetwork.target @8.738s ββnetwork.service @8.484s +253ms ββNetworkManager-wait-online.service @2.836s +5.646s ββNetworkManager.service @2.806s +28ms ββfirewalld.service @2.606s +199ms ββpolkit.service @2.489s +107ms ββbasic.target @2.441s ββpaths.target @2.441s ββcups.path @2.441s ββsysinit.target @2.435s ββsystemd-rfkill@rfkill1.service @2.681s +4ms ββsystem-systemd\x2drfkill.slice @575ms ββsystem.slice ββ-.slice |
httpd has started after both mysqld and networking.
References
- http://php.net/manual/en/filesystem.configuration.php#ini.allow-url-fopen
- https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/SELinux_Users_and_Administrators_Guide/chap-Security-Enhanced_Linux-Introduction.html
- https://www.freedesktop.org/wiki/Software/systemd/NetworkTarget/
- https://bugs.php.net/bug.php?id=11058
thanks.
Thank you for the comment!
My VPS allow_url_fopen = ON
but function file_get_contents still not work …
PHP file_get_contents() is not working when I use PHP version 7.4 so I used PHP Curl.
But when I upgraded my PHP server to 8.0. I can now use file_get_contents()
That is strange! Thank you for sharing the info …
Thank you so much !! You’re a genius !!
π … or I am just very unlucky guy who had misfortune to face all possible issues …
Thx!
wow! I even tried downgrading to php 7.2 from php7.4 and now installing php7.3 with a lot of modules installed and yet the fix was to execute sudo setsebool -P httpd_can_network_connect 1and sudo setsebool -P httpd_unified 1 do the trick for me for centos 8 stream. thank you very much!
Great! Thank you for the feedback!
Searched and searched before I found this. Everyone was telling me about the allow_url_fopen. I had a hunch it was a security issue. But nobody was telling me that or how to fix it until this. The Selinux fix was what did it for me.
Thank you! I am glad that this post helped!