Large Images >3mb Fatal error - Out of memory on save

Setup

VPS Dual Core, 4GB Ram
CENTOS 5.9 x86_64 with access to WHM 11.36.0 (build 21)
Drupal 6.26
PHP 5.3.8 (From Drupal Status Reports Page)
PHP memory limit 512M (From Drupal Status Reports Page)

PHP.INI
memory_limit = 512M
upload_max_filesize = 25M
post_max_size = 25M

Problem

Uploading a JPG image that is only 3.5mb, not using any progress bar just a bare bones drupal install. Upload starts and takes anywhere between 20 seconds and 60 seconds to get one of the following errors.

Error# 1 - Produced when clicking Upload
Create a node -> Click Browse on the cck image -> Upload -> I get a vanilla "An HTTP error 0 occured. /filefield/ahah/[node_type]/[cck_imagefield]/0

Error# 2 - Produced when clicking save instead of upload
Fatal error: Out of memory (allocated 60293120) (tried to allocate 16640 bytes) in /home/[name]/public_html/sites/all/modules/imageapi/imageapi_gd.module on line 59

What to look for

In my case the exact error message when clicking save was "Fatal error: Out of memory (allocated 60293120) (tried to allocate 16640 bytes)". Note that this indicates that only 57.5MB available (thanks to quicksketch for noticing this), so in other words the 512MB indicated in Drupal is not necessarily true.

Solution

I contacted my VPS hosting company for assistance, here is what they say they changed.

  • upload_max_filesize = 100M (from 20mb) - My hosting company claimed this may have helped, even though I don't see how that is possible with a 3.5MB image.
  • Setting in WHM panel >> PHP Configuration Editor. The limit was changed from 256 to 512 Mb - Note that this should NOT have fixed the problem since the 'hard cap seemed to be 57.5mb
  • "php.ini" - The custom php.ini in the website folder had been setup with 512M, however, my hosting company stated that they updated the server-wide PHP.ini but could not give me more information than this.

    The PHP.ini they uploaded was quite different than the quick/simple code you find online. Perhaps some servers require some of these additional lines.

    [PHP]

    engine = On

    short_open_tag = On

    ; Allow ASP-style tags.
    asp_tags = Off

    ; The number of significant digits displayed in floating point numbers.
    precision = 12

    ; Enforce year 2000 compliance (will cause problems with non-compliant browsers)
    y2k_compliance = On

    output_buffering = Off

    zlib.output_compression = Off

    implicit_flush = Off

    unserialize_callback_func=

    ; When floats & doubles are serialized store serialize_precision significant
    ; digits after the floating point. The default value ensures that when floats
    ; are decoded with unserialize, the data will remain the same.
    serialize_precision = 100

    allow_call_time_pass_reference = On

    disable_functions =

    ; This directive allows you to disable certain classes for security reasons.
    ; It receives a comma-delimited list of class names. This directive is
    ; *NOT* affected by whether Safe Mode is turned On or Off.
    disable_classes =

    expose_php = On

    max_execution_time = 200 ; Maximum execution time of each script, in seconds
    max_input_time = 200 ; Maximum amount of time each script may spend parsing request data
    memory_limit = 512M ; Maximum amount of memory a script may consume (32MB)

    error_reporting = E_ALL & ~E_NOTICE & ~E_DEPRECATED

    ; Print out errors (as a part of the output). For production web sites,
    ; you're strongly encouraged to turn this feature off, and use error logging
    ; instead (see below). Keeping display_errors enabled on a production web site
    ; may reveal security information to end users, such as file paths on your Web
    ; server, your database schema or other information.
    display_errors = On

    ; Even when display_errors is on, errors that occur during PHP's startup
    ; sequence are not displayed. It's strongly recommended to keep
    ; display_startup_errors off, except for when debugging.
    display_startup_errors = Off

    ; Log errors into a log file (server-specific log, stderr, or error_log (below))
    ; As stated above, you're strongly advised to use error logging in place of
    ; error displaying on production web sites.
    log_errors = On

    ; Set maximum length of log_errors. In error_log information about the source is
    ; added. The default is 1024 and 0 allows to not apply any maximum length at all.
    log_errors_max_len = 1024

    ; Do not log repeated messages. Repeated errors must occur in same file on same
    ; line until ignore_repeated_source is set true.
    ignore_repeated_errors = Off

    ; Ignore source of message when ignoring repeated messages. When this setting
    ; is On you will not log errors with repeated messages from different files or
    ; sourcelines.
    ignore_repeated_source = Off

    ; If this parameter is set to Off, then memory leaks will not be shown (on
    ; stdout or in the log). This has only effect in a debug compile, and if
    ; error reporting includes E_WARNING in the allowed list
    report_memleaks = On

    ; Store the last error/warning message in $php_errormsg (boolean).
    track_errors = Off

    error_log = error_log

    variables_order = "EGPCS"

    register_argc_argv = On

    ; Maximum size of POST data that PHP will accept.
    post_max_size = 20M

    ; This directive is deprecated. Use variables_order instead.
    gpc_order = "GPC"

    ; Automatically add files before or after any PHP document.
    auto_prepend_file =
    auto_append_file =

    ; As of 4.0b4, PHP always outputs a character encoding by default in
    ; the Content-type: header. To disable sending of the charset, simply
    ; set it to be empty.
    ;
    ; PHP's built-in default is text/html
    default_mimetype = "text/html"
    ;default_charset = "iso-8859-1"

    ; Always populate the $HTTP_RAW_POST_DATA variable.
    ;always_populate_raw_post_data = On

    ;;;;;;;;;;;;;;;;;;;;;;;;;
    ; Paths and Directories ;
    ;;;;;;;;;;;;;;;;;;;;;;;;;

    ; UNIX: "/path1:/path2"
    include_path = ".:/usr/lib/php:/usr/local/lib/php"
    ;

    doc_root =

    ; The directory under which PHP opens the script using /~username used only
    ; if nonempty.
    user_dir =

    ; Directory in which the loadable extensions (modules) reside.
    extension_dir = "/usr/local/lib/php/extensions/no-debug-non-zts-20090626"
    extension=timezonedb.so
    zend_extension="/usr/local/IonCube/ioncube_loader_lin_5.3.so"
    extension="eaccelerator.so"
    eaccelerator.cache_dir="/tmp/eaccelerator"
    eaccelerator.check_mtime="1"
    eaccelerator.compress="1"
    eaccelerator.compress_level="9"
    eaccelerator.debug="0"
    eaccelerator.enable="1"
    eaccelerator.filter=""
    eaccelerator.optimizer="1"
    eaccelerator.shm_max="0"
    eaccelerator.shm_only="0"
    eaccelerator.shm_prune_period="0"
    eaccelerator.shm_size="16"
    eaccelerator.shm_ttl="0"

    enable_dl = On

    ; Whether to allow HTTP file uploads.
    file_uploads = On

    ; Temporary directory for HTTP uploaded files (will use system default if not
    ; specified).
    ;upload_tmp_dir =

    ; Maximum allowed size for uploaded files.
    upload_max_filesize = 100M

    ;;;;;;;;;;;;;;;;;;
    ; Fopen wrappers ;
    ;;;;;;;;;;;;;;;;;;

    ; Whether to allow the treatment of URLs (like http:// or ftp://) as files.
    allow_url_fopen = On

    default_socket_timeout = 60

    [Syslog]

    [mail function]
    ; For Win32 only.
    ;SMTP = localhost
    smtp_port = 25

    ; For Win32 only.
    ;sendmail_from = me@localhost.com

    ; For Unix only. You may supply arguments as well (default: "sendmail -t -i").
    sendmail_path = "/usr/sbin/sendmail -t -i"

    [Java]

    [SQL]
    sql.safe_mode = Off

    [ODBC]
    ;odbc.default_db = Not yet implemented
    ;odbc.default_user = Not yet implemented
    ;odbc.default_pw = Not yet implemented

    ; Allow or prevent persistent links.
    odbc.allow_persistent = On

    ; Check that a connection is still valid before reuse.
    odbc.check_persistent = On

    ; Maximum number of persistent links. -1 means no limit.
    odbc.max_persistent = -1

    ; Maximum number of links (persistent + non-persistent). -1 means no limit.
    odbc.max_links = -1

    ; Handling of LONG fields. Returns number of bytes to variables. 0 means
    ; passthru.
    odbc.defaultlrl = 4096

    ; Handling of binary data. 0 means passthru, 1 return as is, 2 convert to char.
    ; See the documentation on odbc_binmode and odbc_longreadlen for an explanation
    ; of uodbc.defaultlrl and uodbc.defaultbinmode
    odbc.defaultbinmode = 1

    [MySQL]
    ; Allow or prevent persistent links.
    mysql.allow_persistent = On

    ; Maximum number of persistent links. -1 means no limit.
    mysql.max_persistent = -1

    ; Maximum number of links (persistent + non-persistent). -1 means no limit.
    mysql.max_links = -1

    mysql.default_port =

    ; Default socket name for local MySQL connects. If empty, uses the built-in
    ; MySQL defaults.
    mysql.default_socket =

    ; Default host for mysql_connect() (doesn't apply in safe mode).
    mysql.default_host =

    ; Default user for mysql_connect() (doesn't apply in safe mode).
    mysql.default_user =

    mysql.default_password =

    ; Maximum time (in seconds) for connect timeout. -1 means no limit
    mysql.connect_timeout = 60

    ; Trace mode. When trace_mode is active (=On), warnings for table/index scans and
    ; SQL-Errors will be displayed.
    mysql.trace_mode = Off

    [mSQL]
    ; Allow or prevent persistent links.
    msql.allow_persistent = On

    ; Maximum number of persistent links. -1 means no limit.
    msql.max_persistent = -1

    ; Maximum number of links (persistent+non persistent). -1 means no limit.
    msql.max_links = -1

    [PostgresSQL]
    ; Allow or prevent persistent links.
    pgsql.allow_persistent = On

    ; Detect broken persistent links always with pg_pconnect(). Need a little overhead.
    pgsql.auto_reset_persistent = Off

    ; Maximum number of persistent links. -1 means no limit.
    pgsql.max_persistent = -1

    ; Maximum number of links (persistent+non persistent). -1 means no limit.
    pgsql.max_links = -1

    ; Ignore PostgreSQL backends Notice message or not.
    pgsql.ignore_notice = 0

    ; Log PostgreSQL backends Noitce message or not.
    ; Unless pgsql.ignore_notice=0, module cannot log notice message.
    pgsql.log_notice = 0

    [Sybase]
    ; Allow or prevent persistent links.
    sybase.allow_persistent = On

    ; Maximum number of persistent links. -1 means no limit.
    sybase.max_persistent = -1

    ; Maximum number of links (persistent + non-persistent). -1 means no limit.
    sybase.max_links = -1

    ;sybase.interface_file = "/usr/sybase/interfaces"

    ; Minimum error severity to display.
    sybase.min_error_severity = 10

    ; Minimum message severity to display.
    sybase.min_message_severity = 10

    sybase.compatability_mode = Off

    [Sybase-CT]
    ; Allow or prevent persistent links.
    sybct.allow_persistent = On

    ; Maximum number of persistent links. -1 means no limit.
    sybct.max_persistent = -1

    ; Maximum number of links (persistent + non-persistent). -1 means no limit.
    sybct.max_links = -1

    ; Minimum server message severity to display.
    sybct.min_server_severity = 10

    ; Minimum client message severity to display.
    sybct.min_client_severity = 10

    [dbx]

    dbx.colnames_case = "unchanged"

    [bcmath]
    ; Number of decimal digits for all bcmath functions.
    bcmath.scale = 0

    [browscap]
    ;browscap = extra/browscap.ini

    [Informix]
    ; Default host for ifx_connect() (doesn't apply in safe mode).
    ifx.default_host =

    ; Default user for ifx_connect() (doesn't apply in safe mode).
    ifx.default_user =

    ; Default password for ifx_connect() (doesn't apply in safe mode).
    ifx.default_password =

    ; Allow or prevent persistent links.
    ifx.allow_persistent = On

    ; Maximum number of persistent links. -1 means no limit.
    ifx.max_persistent = -1

    ; Maximum number of links (persistent + non-persistent). -1 means no limit.
    ifx.max_links = -1

    ; If on, select statements return the contents of a text blob instead of its id.
    ifx.textasvarchar = 0

    ; If on, select statements return the contents of a byte blob instead of its id.
    ifx.byteasvarchar = 0

    ; Trailing blanks are stripped from fixed-length char columns. May help the
    ; life of Informix SE users.
    ifx.charasvarchar = 0

    ; If on, the contents of text and byte blobs are dumped to a file instead of
    ; keeping them in memory.
    ifx.blobinfile = 0

    ; NULL's are returned as empty strings, unless this is set to 1. In that case,
    ; NULL's are returned as string 'NULL'.
    ifx.nullformat = 0

    [Session]
    ; Handler used to store/retrieve data.
    session.save_handler = files

    session.save_path = /tmp

    ; Whether to use cookies.
    session.use_cookies = 1

    ; Name of the session (used as cookie name).
    session.name = PHPSESSID

    ; Initialize session on request startup.
    session.auto_start = 0

    ; Lifetime in seconds of cookie or, if 0, until browser is restarted.
    session.cookie_lifetime = 0

    ; The path for which the cookie is valid.
    session.cookie_path = /

    ; The domain for which the cookie is valid.
    session.cookie_domain =

    ; Handler used to serialize data. php is the standard serializer of PHP.
    session.serialize_handler = php

    session.gc_probability = 1
    session.gc_divisor = 100

    ; After this number of seconds, stored data will be seen as 'garbage' and
    ; cleaned up by the garbage collection process.
    session.gc_maxlifetime = 1440

    session.bug_compat_42 = 1
    session.bug_compat_warn = 1

    ; Check HTTP Referer to invalidate externally stored URLs containing ids.
    ; HTTP_REFERER has to contain this substring for the session to be
    ; considered as valid.
    session.referer_check =

    ; How many bytes to read from the file.
    session.entropy_length = 0

    ; Specified here to create the session id.
    session.entropy_file =

    session.cache_limiter = nocache

    ; Document expires after n minutes.
    session.cache_expire = 180

    session.use_trans_sid = 0

    url_rewriter.tags = "a=href,area=href,frame=src,input=src,form=,fieldset="

    [MSSQL]
    ; Allow or prevent persistent links.
    mssql.allow_persistent = On

    ; Maximum number of persistent links. -1 means no limit.
    mssql.max_persistent = -1

    ; Maximum number of links (persistent+non persistent). -1 means no limit.
    mssql.max_links = -1

    ; Minimum error severity to display.
    mssql.min_error_severity = 10

    ; Minimum message severity to display.
    mssql.min_message_severity = 10

    ; Compatability mode with old versions of PHP 3.0.
    mssql.compatability_mode = Off

    mssql.secure_connection = Off

    [Assertion]

    [com]

    [Printer]

    [mbstring]

    [FrontBase]

    [Crack]

    [exif]

    extension=pdo.so
    extension=pdo_sqlite.so
    extension=sqlite.so
    date.timezone=America/Edmonton
    zend_extension="/usr/local/Zend/lib/Guard-5.5.0/php-5.3.x/ZendGuardLoader.so"