Normal view

There are new articles available, click to refresh the page.
Before yesterdayOJS /OMP

When Your OJS Journals Start Showing Each Other’s Content

March 9th 2026 at 11:17 pm

A real-world debugging story about Memcached key collisions, caching layers, and why the same bug can hide for months — until it doesn’t.

March 2026  ·  OJS-Services.com

If you’re managing multiple OJS journals on the same server, here’s a scenario that might sound familiar: you update the current issue on one journal, and a few minutes later, a completely different journal’s homepage is showing that same issue. Or worse — users are seeing a journal they’ve never heard of, with a ‘View All Issues’ link that goes nowhere.

We ran into exactly this. Multiple OJS 3.3.x installations on a shared hosting environment, all seemingly independent, but quietly contaminating each other’s data through a shared Memcached instance. Here’s what happened, how we tracked it down, and what actually fixed it.

 

The Setup

We manage a portfolio of academic journals running on Open Journal Systems (OJS). Several of them are hosted on the same server — each with its own subdomain, its own database, its own OJS installation. Completely separate, or so we thought.

The server runs SiteGround’s shared hosting stack. SiteGround offers several caching layers out of the box:

  • NGINX Direct Delivery — static file serving for images, CSS, JS
  • Dynamic Cache — full-page HTML caching
  • Memcached — object-level caching, shared across all sites on the account

 

That last one is the key detail. Memcached runs as a single shared service at 127.0.0.1:11211 — and every OJS installation on the account was configured to use it.

 

What We Saw

The first symptom was a PHP Fatal Error appearing on the homepage of one journal:

Fatal error: Call to a member function getPublished() on null

in classes/journal/SectionDAO.inc.php on line 334

 

The error trace pointed to getByIssueId(18). Except — issue_id 18 didn’t exist in that journal’s database. The highest issue_id was 11.

So where was 18 coming from?

We checked everything: the issues table, publication_settings, journal_settings, url_path fields. Nothing. The database was perfectly correct. The right current issue was set. Yet OJS was trying to load issue 18 on every homepage request.

This is one of those bugs that PHP 8.0 exposed rather than created. On PHP 7.x, calling a method on null returns null and moves on. On PHP 8.0, it throws a Fatal Error. The underlying problem existed before — it just wasn’t visible.

 

The Cache Trail

After ruling out database issues, we turned to caching. We deleted the entire /cache/ directory. The error came back immediately on the next request. We cleared SiteGround’s Dynamic Cache. Same result — gone for a moment, then back.

Then we tried something almost accidental: switching the journal’s theme in the OJS admin panel. The error disappeared. We switched back to the original theme. It stayed fixed — for a while.

The reason? Switching themes triggers OJS’s internal cache flush, which includes Memcached. The stale data was cleared. But the next time OJS populated the cache, it pulled the wrong data again.

This pointed clearly at Memcached. The object cache was storing the wrong issue_id, and no amount of file cache clearing would touch it.

 

The Real Problem: Key Collisions

Here’s what was actually happening. OJS builds Memcached cache keys like this (from MemcacheCache.inc.php):

$this->getContext() . ‘:’ . $this->getCacheId() . ‘:’ . $id

 

For the current issue cache, this produces a key like:

issues:current:1

 

The 1 at the end is the journal_id. And here’s the problem: every fresh OJS installation assigns journal_id = 1 to the first journal. All three of our affected installations had journal_id = 1.

So Journal A, Journal B, and Journal C were all reading and writing to the exact same Memcached key. When Journal C updated its current issue, that value was written to issues:current:1. When Journal A loaded its homepage, it read that same key — and got Journal C’s data.

There is no site-specific prefix in OJS 3.3.x’s Memcached implementation. If two installations share the same Memcached instance and both have journal_id = 1 (the default), they will silently share cached data.

 

The Caching Layer Stack

Before we get to the fix, it’s worth stepping back and looking at the full picture. Modern hosting environments — especially managed ones like SiteGround — can have three or four independent caching layers operating simultaneously:

1. OJS Internal Cache (File-based)

OJS writes cache files to its own /cache/ directory. Clearing this is the first thing most people try. It has no effect on Memcached-stored data.

2. OJS Object Cache (Memcached)

Configured in config.inc.php under [cache]. This is where things like current issue data are stored. If you’re using Memcached on a shared hosting account, this cache is shared at the server level across all sites. This was the source of our problem.

3. Server-Level Dynamic Cache (SiteGround SuperCacher)

SiteGround’s Dynamic Cache stores the complete HTML output of pages. It’s fast, but it can serve stale content even after the database or OJS cache is updated. For OJS journals, we recommend disabling this entirely. OJS has its own caching logic; layering a full-page cache on top creates unpredictable behavior.

4. CDN Cache (Cloudflare)

If your journals are proxied through Cloudflare, you have yet another caching layer in front. Depending on your page rules, Cloudflare can cache HTML pages too. In our setup, some domains were behind Cloudflare — which added another variable to the debugging process when things didn’t clear as expected after a fix.

The tricky part with multiple caching layers is that clearing one doesn’t clear the others. You might flush OJS’s file cache, confirm the database is correct, but Cloudflare is still serving a page from three hours ago. Or SiteGround’s Dynamic Cache is returning a stored response generated before your fix. Always clear in the right order: OJS cache first, then server cache, then CDN.

When something looks wrong on an OJS site and you’ve already confirmed the database is correct, the question becomes: which cache layer am I actually looking at right now?

 

What Didn’t Work

For the record — things we tried that had no effect on the actual collision:

  • Deleting all /cache/ files: Only affects file-based cache, not Memcached
  • Adding memcache_key_prefix to config.inc.php: This option exists in the config template but is not read by MemcacheCache.inc.php in OJS 3.3.x. It does nothing.
  • Clearing Cloudflare cache: Not the source
  • Clearing SiteGround Dynamic Cache: Temporarily removed stale HTML, but Memcached repopulated on the next request
  • Updating the current issue via database: Correct in DB, but immediately overridden by the stale Memcached value

 

The Fix

The solution was a one-line addition to MemcacheCache.inc.php in each affected installation. In the constructor, before adding the server, we set a site-specific prefix using Memcached’s OPT_PREFIX_KEY option:

$this->connection = new Memcached;

// Add this line:

$this->connection->setOption(Memcached::OPT_PREFIX_KEY, md5(__FILE__) . ‘_’);

$this->connection->addServer($hostname, $port);

 

The md5(__FILE__) generates a unique hash from the absolute filesystem path of MemcacheCache.inc.php. Since each OJS installation lives in a different directory, the hash is automatically unique per installation — no manual configuration needed.

After applying this to all three affected installations and flushing Memcached from the SiteGround panel, the cross-site contamination stopped completely.

We also added a null guard to SectionDAO.inc.php to prevent the PHP 8.0 Fatal Error in case a stale cache entry ever surfaces again:

$issue = Services::get(‘issue’)->get($issueId);

if (!$issue) return [];  // Don’t crash on invalid/stale issue_id

 

Why OJS 3.4.x Wasn’t Affected — What the Code Tells Us

The following is based on direct inspection of OJS 3.4.x source files. These are observations and reasoned conclusions, not claims we can fully verify without PKP team confirmation.

 

We had OJS 3.4.x installations running on the same server, with the same journal_id = 1, using the same Memcached instance — and they weren’t experiencing the collision. We wanted to understand why before writing this up.

Looking at the OJS 3.4.x source, the answer appears to be that the Memcached cache path for issue data has been intentionally disabled. In classes/issue/Repository.php, the getCurrent() function contains this comment:

// TODO: Caching as currently setup never properly caches objects

// and always fires a _cacheMiss()

// if ($useCache) {

//     $cache = $this->dao->_getCache(‘current’);

//     return $cache->get($contextId);

// }

 

The Memcached code is commented out. In classes/issue/DAO.php, cache flush calls are similarly disabled with TODO notes. This suggests the PKP team was aware of caching problems during the 3.4.x rewrite and chose to disable this code path temporarily, pending a proper fix.

The result is that OJS 3.4.x reads the current issue directly from the database on every request — no Memcached involved, no collision possible. It’s not that the underlying key collision problem was architecturally solved; it’s that the affected cache path simply isn’t executing.

If Memcached is re-enabled in a future OJS 3.4.x version without adding site isolation, the same collision would likely reappear. The OPT_PREFIX_KEY fix should be applied proactively.

 

Recommendations

If you’re running multiple OJS 3.3.x installations on the same server with Memcached:

  • Apply the MemcacheCache.inc.php prefix fix to every installation sharing the Memcached instance
  • After applying the fix, flush Memcached from your hosting panel to clear any stale cross-site data
  • Disable SiteGround Dynamic Cache for all OJS subdomains — it conflicts with OJS’s own caching
  • If using Cloudflare, bypass cache for dynamic paths (/index.php/*) and only cache static assets
  • When troubleshooting: clear OJS cache first, then server cache, then CDN — in that order

 

For CMS and publishing platforms with their own internal caches, server-level full-page caching (Dynamic Cache, Varnish, etc.) often causes more problems than it solves. Leave object caching to the application; use the CDN for static assets.

 

Wrapping Up

Cache bugs are among the most disorienting to debug because the evidence keeps disappearing. The database looks right, the admin panel looks right, but the site is showing something wrong. When you’re dealing with a multi-layer cache stack and multiple installations sharing infrastructure, the number of possible interactions multiplies fast.

In our case, the bug had probably been present for months, quietly hiding behind PHP 7.x’s silent null handling. The PHP 8.0 upgrade made it impossible to ignore. Sometimes an upgrade doesn’t introduce bugs — it just makes existing ones visible.

We’ve submitted a detailed bug report to the PKP/OJS team with the full analysis and reproduction steps. If you’re running a similar multi-site OJS setup and seeing strange homepage behavior, Memcached key collisions should be high on your list of suspects.

 

OJS-Services.com

We manage 500+ academic journals on Open Journal Systems. When we run into edge cases like this, we write them up — because someone else is probably dealing with the same thing.

The post When Your OJS Journals Start Showing Each Other’s Content first appeared on OPEN JOURNAL SYSTEM SERVICES.

Removing “View of …” from Article PDF Titles in OJS 3.3

December 13th 2025 at 2:33 pm

In Open Journal Systems (OJS) 3.3, some journals notice that when an article PDF is opened using the
PDF.JS Viewer, the browser tab title appears as “View of Article Title”.
While this is expected behavior, many journal editors and article authors find it unnecessary or distracting.

In some cases, the same article may appear in Google search results both with and without the
“View of …” prefix, which can be confusing and may give the impression that they are different pages.
At the moment, there is no confirmed evidence that this has a direct negative impact on Google Scholar.
However, from an editorial and presentation perspective, many journals prefer to display only the article title.

Why does “View of …” appear?

The PDF viewer page title is built using a translation key in the OJS locale files:
article.pageTitle. In the default English locale, this key is often defined as:
View of {$title}. That’s why the browser tab title becomes “View of …”.

Why this can be undesirable

  • It may look unprofessional or unnecessary to editors and authors.
  • Google search results may show the same article twice (with and without “View of …”).
  • Readers may assume the entries represent different articles.
  • Presentation may feel inconsistent across languages.

What NOT to do

You can remove the prefix by editing core files such as locale/en_US/locale.po
via FTP/SFTP. However, this is not update-safe. Future OJS upgrades can overwrite core locale files,
causing the “View of …” prefix to return.

Recommended solution: Custom Locale Plugin (Update-Safe)

The cleanest approach is to override the translation string using the Custom Locale Plugin,
so you do not modify core files and your change survives updates.

Step 1: Enable the Custom Locale Plugin

Go to Administration → Website Settings → Plugins, then enable
Custom Locale Plugin.

Step 2: Find the correct locale file and key

Important note: the Custom Locale interface does not provide a direct global search box.
After selecting a language, OJS will show a list of locale files for that language.

  1. Open the Custom Locale interface and select the language English (en_US).
  2. After selecting the language, you will see the list of locale files. From the list, open
    locale/en_US/locale.po.
  3. Inside that file, locate the translation key article.pageTitle.
    You can also confirm this key by checking the same file via FTP/SFTP first and noting the exact label to override.

Step 3: Override the page title string

Once you find article.pageTitle, update its value from
View of {$title} to {$title}.
This removes the “View of ” prefix while keeping the article title placeholder intact.

Step 4: Clear cache

After saving the override, clear the OJS cache to ensure the new translation loads.
If you have server access, remove template/cache files from the OJS cache directory (common locations include
cache/t_compile). Then hard refresh your browser.

Result

After applying this override, the PDF viewer page title will display only the article title.
The “View of …” prefix will be removed, and because this is done through Custom Locale, it will remain
in place even after OJS updates.

Final note on indexing

There is no confirmed evidence that this behavior negatively impacts Google Scholar indexing.
Still, removing “View of …” can help keep your journal’s presentation clean and reduce confusion in general
Google search results when duplicate-looking entries appear.

The post Removing “View of …” from Article PDF Titles in OJS 3.3 first appeared on OPEN JOURNAL SYSTEM SERVICES.

Fixing OJS 3.4 Email Sending Issues on Shared Hosting (Bluehost, GoDaddy, HostGator, etc.)

October 13th 2025 at 12:18 am

At OJS Services, we provide installation, upgrade, hosting, and technical support for Open Journal Systems (OJS) across many countries.
Working with hundreds of journals hosted on different servers — Bluehost, GoDaddy, HostGator, Hetzner, IZAhost, and others — allows us to observe version-specific behaviors very closely.

Recently, after many OJS journals upgraded to OJS 3.4, one issue became increasingly common:

Emails appear to be sent successfully, but never reach the recipient.

The Root Cause

With OJS 3.4, PKP introduced a major change to the email system.
The old PHPMailer library was replaced by Symfony Mailer — a modern, secure framework that enforces strict SSL/TLS and authentication rules.

Unfortunately, most shared hosting providers (especially Bluehost, GoDaddy, HostGator) apply strict limits on outgoing SMTP connections from PHP applications.
As a result:

  • SMTP authentication succeeds,
  • OJS reports “Message sent successfully,”
  • but the email quietly disappears in the Exim mail queue.

Meanwhile, when sending through webmail (Roundcube), everything works perfectly — because webmail doesn’t use SMTP.
It uses the local sendmail transport instead.

The Reliable Fix: Use Sendmail Instead of SMTP

The simplest and most reliable fix is to switch OJS from SMTP to sendmail.
This makes OJS send mail directly through the local mail transport agent (Exim/Postfix), bypassing all TLS and firewall restrictions.

Open your config.inc.php file and edit the [email] section like this:

[email]
default = sendmail
sendmail_path = "/usr/sbin/sendmail -t -i"

; SMTP settings can stay for reference but will not be used
smtp = On
smtp_server = box1234.bluehost.com
smtp_port = 587
smtp_auth = tls
smtp_username = editor@yourjournal.org
smtp_password = yourPassword

After saving these settings, OJS will start delivering emails instantly — using the same internal channel that webmail already relies on.

Why This Difference Occurs

In OJS 3.3 and earlier versions, both SMTP and sendmail behaved similarly because PHPMailer handled both transports loosely.
But starting with OJS 3.4, Symfony Mailer enforces strict certificate validation and secure transport layers.

On shared servers, these extra security layers often conflict with provider-side restrictions.
The result: the connection appears successful, but the message is dropped.

sendmail, on the other hand, talks directly to /usr/sbin/sendmail on the same server.
It stays local, avoiding SSL negotiation entirely — which makes it both faster and more compatible with cPanel-based servers.

Field-Tested Experience

We first confirmed this issue with several clients hosted on Bluehost and GoDaddy.
Even with valid SPF, DKIM, and correct SMTP credentials, emails were not reaching inboxes.
After switching to sendmail, all notifications — user registration, password reset, submission acknowledgment — started working immediately.

We later verified the same behavior on HostGator, GoDaddy and Namecheap servers.
In OJS 3.4, sendmail is consistently more reliable than SMTP on shared environments.

Technical Note

This isn’t a new feature — it’s the default configuration that OJS has always recommended.
In the template file config.TEMPLATE.inc.php, the line default = sendmail has been there for years.
However, many users switched to SMTP because it “sounded more professional.”

After the 3.4 update, our tests confirm that on shared hosting, sendmail is the safer choice.

Final Recommendation

If you’re using OJS 3.4 and your emails appear to send but never arrive:

  • Even if SPF, DKIM, and PTR records are correct,
  • Even if your test email shows “Sent successfully,”
    👉 Switch to sendmail first.
    In most cases, that alone solves the issue.

Lessons From Experience

At OJS Services, we provide direct technical support to many academic journals every week.
Our observation is simple: most OJS email problems aren’t caused by the software itself, but by how different hosting providers handle outgoing mail.
Our job is to find the balance between both worlds — reliability and compatibility.

That’s why we now apply this rule for all new OJS 3.4 and 3.5 installations:

“Use sendmail for shared hosting. Use SMTP for dedicated servers.”

It’s simple, stable, and future-proof.

The post Fixing OJS 3.4 Email Sending Issues on Shared Hosting (Bluehost, GoDaddy, HostGator, etc.) first appeared on OPEN JOURNAL SYSTEM SERVICES.

Troubleshooting “HTTP ERROR 500” in OJS (Open Journal Systems)

July 1st 2025 at 7:26 pm

OJS (Open Journal Systems) is a popular open-source platform for managing academic journals—from submission through to peer review and publication. It’s robust and flexible, but like any software, it depends on server environment and configuration to function smoothly.

Sometimes your journal may suddenly stop working or show error pages. One frequent culprit is the dreaded “HTTP ERROR 500” – an “Internal Server Error.” When this happens, your users likely see a blank page or a generic message instead of your journal content.

Let’s look at why this happens and what you can do about it—no guesswork, just tested advice.

What Does “HTTP ERROR 500” Mean?

This error indicates the server encountered something unexpected it couldn’t handle. In OJS, it may occur when loading the homepage, accessing the backend, or using plugins.

Common Causes & Fixes

1. Server Environment Issues

  • PHP version or missing extensions
    OJS generally requires PHP 7.x or 8.x, along with extensions like xml, gd, intl, pdo_mysql, and fileinfo. If an expected function is missing (for example, xml_parser_create()), PHP throws a 500 error.
    Fix: Check your PHP environment and install missing modules. On many Linux systems:
    sudo apt install php-xml php-gd php-intl
    

    Then restart PHP and your webserver.

  • File permissions
    OJS needs to read and write to certain files—particularly config.inc.php, cache folders, and your files_dir. If these aren’t writable, errors occur. The core config.inc.php file must exist—it lives at your OJS installation root, not in a “config” folder. Permissions like 644 for files and 755 for directories are usually enough. Certain directories (cache, files dir) may require 775 or 777.
  • Error logs
    You won’t fix what you can’t see. Check your PHP-FPM logs (like /var/log/php‑fpm/www-error.log) or Apache/Nginx logs. They often contain hints like “permission denied” or “undefined function” messages.

2. OJS Configuration & Caching

  • config.inc.php settings
    All key options—database credentials, files_dir path, and security settings—live here. Errors in this file are a major source of HTTP 500s. The file must be present, correct, and readable by the webserver.Check:
    ; [files]
    files_dir = /full/path/to/ojsdata
    

    And verify this directory exists and is writable.

  • Plugin conflicts
    A recently installed or updated plugin may break OJS and trigger a 500. Disable the plugin via the database or temporarily rename its folder to test.
  • Corrupted cache
    Old files in cache/, cache/t_cache, cache/t_config, or cache/t_compile can cause issues. Clear them manually and reload your site to let OJS rebuild fresh cache.

3. Server Limits & SSL

  • Resource limits
    Tasks like upgrading OJS or exporting issues may exceed time or memory limits (max_execution_time, memory_limit). Too much and the server aborts with a 500.
    Fix: Raise these limits in php.ini or .htaccess, or run heavy tasks from the command line.
  • SSL or HTTPS misconfiguration
    Enabling SSL means updating server certs and also adjusting OJS’s config.inc.php (force_ssl = On). A mismatch or missing certificate can also cause a 500.

Quick Fix Checklist

  1. Check logs—PHP‑FPM and web server logs for error messages.
  2. Confirm PHP modules—especially XML, GD, intl, PDO.
  3. Validate config.inc.php—exists, readable, correct paths (especially files_dir).
  4. Fix permissions—ensure OJS folders & files are writable by the PHP user.
  5. Clear cache—empty all cache directories.
  6. Disable suspect plugins.
  7. Increase resource limits—for heavy operations.
  8. Check SSL settings—ensure SSL is set up cleanly.

Still Stuck?

If you’ve tried all of the above and the site still shows a 500 error, we’re here to help. Reach out to us via our contact page and let our team help get your journal back online.

The post Troubleshooting “HTTP ERROR 500” in OJS (Open Journal Systems) first appeared on OPEN JOURNAL SYSTEM SERVICES.

❌
❌