Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Php Apache Tika Laravel Package

vaites/php-apache-tika

PHP bindings for Apache Tika that extract text, HTML, and metadata from documents, images, and other formats. Run the JAR via CLI or use the faster Tika server mode over HTTP. Supports local and remote resources, OCR, and Apache Tika 1.15+.

View on GitHub
Deep Wiki
Context7

Getting Started

The package is a thin, dependency-free PHP client — there is no Laravel service provider, facade, or config file to publish. You wire it yourself, which takes about five minutes.

1. Install the package

composer require vaites/php-apache-tika

2. Decide on a mode before writing any code. This is the single most important early decision:

  • Server mode (recommended): talk HTTP to a running Tika Server. ~5x faster, no JVM spawned per request, survives concurrency. Run it with Docker: apache/tika:latest-full on port 9998.
  • App mode: point the client at tika-app.jar and it shells out to java -jar. Zero infrastructure, but each call pays JVM startup (~2–5s) and you must have a JRE on every host.

For a Laravel app that will process uploads on a queue, use server mode. Add Tika to docker-compose.yml alongside MySQL and Redis:

tika:
  image: apache/tika:latest-full   # "full" includes OCR + more parsers
  ports: ["9998:9998"]

3. Bind a configured client in a service provider. Because the underlying Client is a mutable singleton-ish object, register it as a singleton and configure it once in AppServiceProvider::register():

$this->app->singleton(\Vaites\ApacheTika\Client::class, function () {
    $client = \Vaites\ApacheTika\Client::make(
        config('tika.host', 'tika'),
        config('tika.port', 9998)
    );
    $client->setTimeout(config('tika.timeout', 60));
    return $client;
});

4. First use case: extract text from an uploaded PDF.

$text = app(\Vaites\ApacheTika\Client::class)
    ->getText(Storage::path($request->file('resume')->store('resumes')));

From there, the obvious next steps are getMetadata() for author/page-count/MIME data, and getJSON() when you want a single call returning both.

Where to look first: the README's mode comparison and the client source (src/Client.php, src/Client/AppClient.php, src/Client/ServerClient.php). There is no Laravel glue to read, so the client classes are the documentation.

Implementation Patterns

Wrap the client in a domain service. Don't let Client leak into controllers — it has a wide surface (getText, getHTML, getJSON, getMetadata, getLanguage, detectLanguage, getMimeType, getRecursiveText) and you'll want to swap or mock it later.

final class DocumentExtractor
{
    public function __construct(private \Vaites\ApacheTika\Client $tika) {}

    public function extract(string $path): ExtractedDocument
    {
        $json = $this->tika->getJSON($path);          // text + metadata in one round trip
        return new ExtractedDocument(
            text: $json->getText(),
            metadata: (array) $json->getMetadata(),
        );
    }
}

Always extract on a queue for anything user-supplied. A 40-page scanned PDF with OCR can take tens of seconds; doing it synchronously in a POST handler will hit PHP's max_execution_time and your users' patience.

class ExtractDocumentJob implements ShouldQueue
{
    public int $timeout = 300;
    public int $tries = 3;

    public function __construct(public Document $document) {}

    public function handle(DocumentExtractor $extractor): void
    {
        $result = $extractor->extract(
            Storage::disk('documents')->path($this->document->path)
        );

        $this->document->update([
            'text' => $result->text,
            'meta' => $result->metadata,
            'indexed_at' => now(),
        ]);
    }
}

Use getRecursiveText() for archives and email containers (.zip, .eml, .msg). Plain getText() on a zip returns the container's own metadata, not the contents — a common source of "why is my extraction empty?" bugs.

Pattern for search/RAG pipelines: use getText() for the chunked body you embed, and a separate cheap getMimeType() call as a gate before you spend time on parsing. Store the MIME Tika detects rather than trusting the client-supplied Content-Type or the file extension.

Testing. Bind a fake extractor in the container and assert jobs dispatch; keep one integration test tagged @group tika that hits a real server in CI. Do not attempt to unit-test the client itself — it is a transport.

Multi-tenant / per-tenant resources. If you run multiple Tika servers, key the singleton by tenant and resolve per-request rather than reconfiguring a shared instance.

Gotchas and Tips

  • The client is stateful. setTimeout, setOCRLanguage, setMaxFileSize, setDownloadRemote, setUserAgent, setRetries mutate the instance and persist for later calls in the same request/worker. Configure once at resolution time; never toggle options mid-request.
  • Queue workers reuse the connection. A singleton HTTP client held across many jobs can hit stale sockets after an idle period or a Tika restart. Either reset the binding in JobProcessing or accept occasional retries — set $tries > 1 and treat connection exceptions as retryable.
  • setDownloadRemote(true) is a remote-file-inclusion footgun. If enabled, a user-supplied string passed as the "path" can make Tika fetch a URL (SSRF). Keep it off; always pass a real local filesystem path.
  • Server readiness is not guaranteed by depends_on. Tika takes ~10–20 s to boot. Add a healthcheck on GET /tika (or just /) before starting the app/worker container, otherwise the first job in CI fails.
  • App mode needs java on PATH and the JAR path to be absolute. A missing JRE throws a fairly opaque process-execution error. Pin the JAR version and store it outside vendor/ so a composer install can't wipe it.
  • Memory. Tika Server's JVM heap is the usual failure point: -Xmx512m default won't parse a 200 MB scanned PDF. Set JAVA_OPTS on the container and enforce a max upload size in Laravel that is smaller than what Tika can handle.
  • Timeouts are separate layers. The client's setTimeout covers the HTTP read; PHP's max_execution_time and the queue's $timeout cover the job. Set them in descending order (queue > Tika timeout > 2× expected parse time).
  • OCR is not on by default. It requires Tesseract installed inside the Tika image and an OCR language via setOCRLanguage('eng'). The latest-full image includes it; the slim image does not.
  • Encodings. Non-UTF-8 legacy .doc/.txt files can come back mangled. Run the output through mb_convert_encoding($text, 'UTF-8', 'auto') before storing, and make the DB column utf8mb4.
  • Empty text ≠ failure. Image-only PDFs and DRM-protected files return an empty string without error. Always branch on mb_strlen($text) === 0 and mark the document as needing OCR rather than treating it as success.
  • Errors surface as exceptions, not return codes. Wrap getText/getJSON calls and map to your own domain exception so retries treat them as transient, and so callers don't need to catch (\Throwable).
  • Extension points are limited. There is no plugin system; if you need custom parsing, your options are (a) point app mode at a custom JAR, (b) put your own Tika config in TIKA_CONFIG on the server, or (c) post-process the returned text. There is no hook to intercept the request.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
dakiquang/laravel-oauth-refresh-lock
woda/laravel-worktrees
dalefranks/ramasite
faghy/laracashbook
roundly-consulting/google-places-for-laravel
roundly-consulting/kubernetes-api-for-laravel
roundly-consulting/plausible-for-laravel
gvp/gvp-laravel-template
metasyncsite/laravel-metasync-client
roundly-consulting/onboarding-for-laravel
andydefer/laravel-notification
adachsoft/cli-process-tester
jhaskell13/laraflow
sebastienheyd/boilerplate-media-manager
ccast/tagixo-primix
pretendtrue/laravel-builder
sawmainek/laravel-scout-tntsearch-driver
tomshaw/laravel-calendar-table
dibakar/laravel-ownership
adachsoft/changelog-linter