PHP Development

PHP Disabled Functions on Shared Hosting: Why, and What to Do Instead

By the Domain India teamPublished 15 min read
Knowledge base article
Contents (9 sections)

Your script works on your laptop and then fails on the server with exec() has been disabled for security reasons. That is not a broken account or a bug in your code: shared hosting switches off a small group of PHP functions that would let one website reach past its own account. This guide covers which functions those are, what they break in real projects — Composer, framework email, schedulers, image and PDF tools — and what to do instead.

Key takeaways

Shared servers disable the PHP functions that start other programs (exec, shell_exec, system, passthru, proc_open, popen) and some that open raw network sockets (fsockopen, stream_socket_client), so that one compromised website cannot attack every other account on the machine. The list is a server setting and differs between servers and PHP versions, so read your own with ini_get('disable_functions') rather than assume. It cannot be switched on for a single account. Most projects have a working alternative — mail() with -f instead of SMTP, building locally and uploading instead of running Composer on the server, pure-PHP libraries instead of shelling out — and an application that genuinely must run programs belongs on a VPS or the App Platform.

1. How to recognise a disabled function

PHP does not remove these functions; it refuses to run them, and says so by name. A framework usually wraps the same sentence into an exception:

code
Warning: exec() has been disabled for security reasons in /home/user/public_html/tools.php on line 14
The error message tells you exactly what to fix

"Has been disabled for security reasons" means the server blocked one named function. That is different from "Call to undefined function", which means a PHP extension is missing, and different from a 500 error with no message, which is usually a syntax or permission problem.

If the page is blank, error display is off, which is correct for a live site, and the message is in your error log instead — see reviewing error logs in cPanel and DirectAdmin, or your application's own log such as storage/logs/laravel.log.

2. Why shared hosting disables them

On a shared server many customer accounts live on one machine. CloudLinux gives each account its own view of the filesystem, Imunify360 scans for malware, and a web application firewall filters requests. Disabling functions closes the last door: the one an attacker walks through after a weak plugin or a stolen FTP password lets them upload a single PHP file.

That file is only dangerous if it can do something. With exec() or proc_open() it can run any command the web user can — download a malware kit, start a spam run, scan the local network, mine cryptocurrency with your CPU quota. With raw sockets it can connect out to anything, turning a contact form into a spam relay. And the damage is never limited to the hacked site: a spam run gets the server's IP blacklisted, and then every customer on it has email problems.

Disabling these functions keeps "one site was hacked" inside one account. It is standard practice across the industry, not a Domain India policy, which is also why an application written for a VPS sometimes needs adjusting before it runs on shared hosting anywhere.

3. Which functions are usually disabled

A typical shared-hosting list covers these groups. Treat it as the shape of a list, not a copy of your server's.

GroupTypical examplesWhy they are blocked
Running other programsexec, shell_exec, system, passthru, proc_open, popenShell access from a web page: the single biggest risk
Process controlpcntl_fork, pcntl_exec, posix_kill, posix_setuidOverloading the server, attempts at privilege escalation
Raw network socketsfsockopen, pfsockopen, stream_socket_client, stream_socket_server, socket_createSpam relays, port scanning, data theft; a listening socket is a backdoor
Parallel cURLcurl_multi_execFlooding other servers from your account
Filesystem linkssymlink, linkHistorically used to read other accounts' files
Changing the enginedl, ini_alterWould let a script undo the restrictions above
Revealing configurationshow_source, highlight_file, and on some servers phpinfoLeaks database passwords, paths and keys

Two things matter before you plan around this. The exact list differs: it is a server setting, so two servers can carry different lists, and one server can apply a different list to a different PHP version. And it usually applies on the command line too: the restriction is normally set on the whole PHP engine, so php run over SSH is bound by the same list as PHP run by the web server. On at least one of our cPanel servers, this is exactly how it is configured — which is why the next section exists.

Ordinary outbound HTTPS keeps working

On our cPanel servers, curl_exec() and file_get_contents() on an https:// URL are not socket functions in this sense and normally keep working, so payment gateways, REST APIs and webhooks are fine. On our DirectAdmin servers, curl_exec and curl_multi_exec are usually disabled for websites as well; allow_url_fopen is on, so file_get_contents() on an https:// URL works and an HTTP client such as Guzzle or Symfony HttpClient can fall back to PHP's own HTTPS stream wrapper — if yours cannot, ask support. On Webuzo, check with ini_get('disable_functions') or ask support. Where curl_multi_exec is disabled, a well-written HTTP client such as Guzzle falls back to sending requests one at a time.

4. What it breaks: Composer and deployment over SSH

Jailed SSH access is available on every cPanel, DirectAdmin and Webuzo plan; it is off by default, so ask support to enable it. It is useful for Git and file work, but it does not get you past the disabled functions: proc_open, popen, exec and shell_exec are disabled on both our cPanel and DirectAdmin shared servers, and on cPanel that includes the command-line PHP you run over SSH.

Composer cannot run without those functions. Even the most cautious install, composer install --prefer-dist --no-scripts, needs proc_open to start git or unzip, so it stops with proc_open() has been disabled for security reasons before your project is built. composer create-project laravel/laravel fails the same way.

Composer does not run on shared hosting

If Composer stops with proc_open() has been disabled for security reasons, no flag or setting fixes it on a shared server. Build on your computer or in CI and upload the finished project, as described below.

What to do instead. Run composer install on your own computer or in your CI pipeline, where nothing is disabled, then upload the project including the vendor folder with File Manager or SFTP. It is faster, and it keeps build failures off your live site. For Laravel, Path A in deploying Laravel on cPanel walks through this route, including the .env, application key, document root and database steps; for a general PHP project, see installing PHP libraries with Composer. The limit applies to PHP starting programs, not to you: on our cPanel servers git is available inside the jailed shell, so you can run Git yourself over SSH, but Composer cannot start git for you. See deploying with Git.

5. What it breaks: your framework's email transport

This one costs the most time, because the application looks correctly configured and mail simply never leaves.

Laravel 9 and later, Symfony and most modern frameworks send through Symfony Mailer. Its SMTP transport opens a socket with stream_socket_client; its sendmail transport starts a process with proc_open. Where those are disabled both fail, and the SMTP credentials you configured are never even used. PHP's own mail() is unaffected, because it hands the message to the server's local mail system instead of opening a connection itself.

What to do instead, in order of effort:

  1. PHP mail() with the -f envelope sender. The dependable route on shared hosting. The -f matters: without it the envelope sender is the server's hostname, SPF does not align with your domain, and your mail goes to spam. In Laravel or Symfony, a short custom transport class that calls mail() plugs into the existing Mail:: API, so your application code does not change.
  2. A transactional email API over HTTPS. Amazon SES, Postmark, Mailgun or Brevo accept mail over an ordinary HTTPS request, which is not blocked, and most frameworks ship an API transport.
  3. Move the application to a VPS or the App Platform, where SMTP works normally.

PHP sendmail settings has working code for all three, plus the SPF, DKIM and DMARC records you need before any of it reaches an inbox.

6. What it breaks: schedulers, queues and tools that shell out

Laravel's scheduler. The single cron job that runs php artisan schedule:run works (every 4 minutes at most on shared hosting), but each Schedule::command(...) task is launched as a child process, which needs proc_open — so scheduled artisan commands fail while the scheduler itself appears to run. Either register the work as Schedule::call(...) or Schedule::job(...), which run inside the same PHP process, or give each task its own cron entry calling php artisan your:command directly. See how to set up a cron job.

Queue workers. A long-running queue:work daemon is unsuitable for shared hosting anyway, and it relies on process signal handling. Run the queue from cron with --stop-when-empty, or use the sync driver for low volumes.

Anything that shells out to a command-line tool. The largest group of broken libraries:

What you were doingWhat to do instead
Image resizing by calling ImageMagick's convert binaryThe GD extension, or the Imagick PHP extension if it is enabled for your PHP version: both work inside PHP
HTML to PDF with wkhtmltopdf or headless ChromeA pure-PHP library such as Dompdf, mPDF or TCPDF
Video or audio conversion with FFmpegA media-processing API, a VPS, or the App Platform
Downloader tools of the youtube-dl or yt-dlp kindNot possible on shared hosting; use a VPS
php artisan storage:link (needs symlink)Create the link with ln -s if jailed SSH is enabled on your account, or ask our support team to create it
Backup plugins that call mysqldump or zipThe control panel's backup tools and phpMyAdmin export, or a plugin that archives in pure PHP

Before concluding a library is unusable, check its documentation for a pure-PHP mode. Many have one and merely prefer the faster binary when it is available.

7. How to see the list for your own account

  1. A phpinfo page.
    Create info.php in public_html containing <?php phpinfo(); and open https://yourdomain.com/info.php. Search for disable_functions; the "Local Value" column is what applies to you. If the page is blank or shows a disabled-function warning, phpinfo itself is blocked on that server, so use method 2 or 3.
  2. Ask PHP from your own code.
    Put <?php echo ini_get('disable_functions'); in a temporary file and open it. This always works, because ini_get is never on the list, and it prints the effective value. To test one function, use function_exists('proc_open'), which returns false when it is disabled.
  3. Over SSH. With jailed SSH enabled on your account (it is off by default; ask support), run `php -i
    grep disable_functions, naming the version you use where your panel offers several, for example ea-php83 -i | grep disable_functions. Do not read a php.ini file instead: the setting is often applied from an additional configuration file, so the main php.ini` can look empty while functions are very much disabled.
Delete the test file when you are finished

A phpinfo page left in public_html publishes your server paths, PHP configuration and loaded extensions to anyone who finds it, and bots look for exactly these filenames. Check it, note what you need, then delete the file. The same goes for the ini_get test file.

Getting jailed SSH switched on and logging in with a key: enabling and accessing jailed SSH. Changing versions: PHP version management.

8. What you can and cannot change

A disabled function cannot be enabled for one account. disable_functions is applied to the PHP engine, and a per-account setting can only add restrictions, never restore one the server has removed. ini_set(), .user.ini and .htaccess all fail at this, and so does switching PHP version. Anyone describing a trick that gets around it is describing a security hole.

That leaves two honest paths:

  • Adapt the application. For most projects this is small: mail() with -f instead of SMTP, a pure-PHP PDF or image library instead of a binary, Composer on your computer instead of on the server, separate cron entries instead of a process-spawning scheduler. Sections 4 to 6 are this path.
  • Move to a server you control. If the application's purpose requires running programs — media processing, a persistent worker, a tool that wraps a CLI binary — it needs its own environment.

Not sure which side your project is on? Open a ticket at /support/ticket with the exact error, and our team will tell you what your server allows and whether a workaround exists.

9. Where Domain India fits

Our cPanel, DirectAdmin and Webuzo shared plans include a choice of PHP versions and jailed SSH access on request (it is off by default; ask support), and the cPanel and DirectAdmin servers add Node.js and Python app tools in the control panel. The cPanel and DirectAdmin servers also run CloudLinux account isolation, Imunify360, a web application firewall and DDoS protection, and every plan includes free SSL and backups (weekly on cPanel and DirectAdmin, nightly on Webuzo). WordPress, Joomla, most PHP applications and normal Laravel apps run there without ever touching a disabled function.

When your code genuinely has to run programs, there are two ways up. The App Platform (PaaS) runs your application in its own container, so nothing is disabled: deploy by Git push or from GitHub, and we run the servers, SSL and PostgreSQL.

App Starter
₹100/mo + GST
  • 512 MB RAM per app
  • 1 vCPU
  • 5 GB NVMe SSD
  • PostgreSQL Database
See plan details

A VPS gives you root access to a whole machine: install FFmpeg or ImageMagick, set your own php.ini, run Docker and persistent workers. In exchange you look after the operating system, updates, security and backups. Read VPS hosting compared with shared hosting before deciding.

VPS Starter
₹552.65/mo + GST
  • 1 vCPU
  • 2 GB DDR4 RAM
  • 64 GB NVMe SSD Storage
  • 2 TB Monthly Bandwidth
See plan details

Prices shown are Domain India list prices on 20 September 2026 and exclude 18% GST.

Why does my PHP script say a function "has been disabled for security reasons"?

The server's PHP configuration blocks that function. On shared hosting, the functions that run other programs (exec, shell_exec, system, passthru, proc_open, popen) and some that open raw network sockets (fsockopen, stream_socket_client) are disabled, so that a single hacked website cannot attack the rest of the server.

Can you enable exec() or proc_open() for my account only?

No. disable_functions applies to the PHP engine, and an account-level setting can only add restrictions, never remove one; switching PHP version does not lift it either. An application that truly needs to run programs needs a VPS or our App Platform, where nothing is disabled.

How do I find out which functions are disabled on my server?

Put <?php echo ini_get('disable_functions'); in a temporary PHP file, open it in your browser, then delete the file. Over jailed SSH, if it is enabled on your account, run php -i | grep disable_functions, and use function_exists('proc_open') to test one function. Our support team can also tell you the current list, which differs between servers and PHP versions.

Composer is listed in my plan, so why does it fail?

Composer needs proc_open to start git and unzip, even for composer install --prefer-dist --no-scripts, and proc_open is disabled on our shared servers, so Composer cannot run there. Run Composer on your own computer or in CI, then upload the project including its vendor folder.

Why does my Laravel or PHPMailer SMTP email fail while a plain PHP contact form works?

SMTP opens a network socket with stream_socket_client, and the sendmail transport starts a process with proc_open; both can be disabled. PHP's mail() is not, because it passes the message to the server's local mail system. Use mail() with the -f envelope sender, or an email API over HTTPS.

Does this affect WordPress?

Normal WordPress does not use these functions and runs without trouble. What can hit the limit is backup plugins that call mysqldump or zip, image plugins that shell out to ImageMagick, and SMTP plugins where socket functions are blocked. Use the control panel's backups, a pure-PHP alternative, or the plugin's HTTPS API mailer.

Can I run FFmpeg, wkhtmltopdf or yt-dlp on shared hosting?

No. Those are external programs, and PHP cannot start them on shared hosting even where the binary exists. Use a pure-PHP library where one exists, such as Dompdf for PDFs and GD or Imagick for images, or move the work to a VPS or the App Platform.

Ready to get your application running? Compare cPanel, DirectAdmin and Webuzo hosting, check the hosting compatible technologies list before you build, or look at the App Platform and VPS plans if your project needs to run its own programs.

Not sure whether your app will run on shared hosting?

Send us the exact error message and what your application needs to do. We will tell you what your server allows, whether a workaround exists, and which plan fits if it does not.

Ask our support team

Was this article helpful?

Your answer helps us decide what to improve next.

Still need help? Open a support ticket and our team will reply.

Prefer an app? Add this site to your home screen.Get the app