Sebelum memulai praktik, pastikan Anda telah memahami konsep dasar pada materi kelas AI Agent & PHP di infokoding.

BAB 13

Tool Membaca File

Implementasi tool pembaca file untuk AI Agent PHP: ekstraksi konten dari PDF, TXT, DOCX, CSV, dan JSON dengan keamanan path traversal protection dan batasan ukuran file.

Terakhir diperbarui:

TL;DR (Ringkasan Cepat)

  • Selalu validasi path file untuk mencegah Path Traversal Attack.
  • Batasi ukuran file yang bisa dibaca (maks ~10MB untuk mencegah memory exhaustion).
  • Gunakan library seperti smalot/pdfparser untuk ekstraksi teks dari PDF.
  • Potong teks yang terlalu panjang sebelum dikirim ke AI untuk menghemat token.

Instalasi Library Parsing File

composer require smalot/pdfparser
# PhpWord untuk DOCX
composer require phpoffice/phpword

FileTool Class

<?php

namespace App\Tools;

class FileTool implements ToolInterface
{
    private string $allowedDir;
    private int $maxFileSizeBytes;
    private int $maxChars;

    public function __construct(
        string $allowedDir = './uploads',
        int $maxFileSizeMB = 10,
        int $maxChars = 8000
    ) {
        $this->allowedDir       = realpath($allowedDir) ?: $allowedDir;
        $this->maxFileSizeBytes = $maxFileSizeMB * 1024 * 1024;
        $this->maxChars         = $maxChars;
    }

    public function getDefinition(): array
    {
        return [
            'type'     => 'function',
            'function' => [
                'name'        => 'read_file',
                'description' => 'Membaca dan mengekstrak teks dari file lokal. Mendukung format: PDF, TXT, CSV, JSON, DOCX.',
                'parameters'  => [
                    'type'       => 'object',
                    'properties' => [
                        'filename' => [
                            'type'        => 'string',
                            'description' => 'Nama file (hanya nama file, bukan path lengkap)',
                        ],
                    ],
                    'required' => ['filename'],
                ],
            ],
        ];
    }

    public function execute(array $args): mixed
    {
        $filename = basename($args['filename'] ?? ''); // basename() mencegah path traversal
        $filepath = $this->allowedDir . DIRECTORY_SEPARATOR . $filename;

        // Security: Pastikan file ada dalam direktori yang diizinkan
        $realPath = realpath($filepath);
        if (!$realPath || !str_starts_with($realPath, $this->allowedDir)) {
            return ['error' => 'Akses file ditolak: path tidak valid'];
        }

        if (!file_exists($realPath)) {
            return ['error' => "File '$filename' tidak ditemukan"];
        }

        if (filesize($realPath) > $this->maxFileSizeBytes) {
            $maxMB = $this->maxFileSizeBytes / 1024 / 1024;
            return ['error' => "File terlalu besar. Maksimum ukuran file: {$maxMB}MB"];
        }

        $extension = strtolower(pathinfo($realPath, PATHINFO_EXTENSION));

        $text = match ($extension) {
            'txt'  => file_get_contents($realPath),
            'json' => $this->readJson($realPath),
            'csv'  => $this->readCsv($realPath),
            'pdf'  => $this->readPdf($realPath),
            'docx' => $this->readDocx($realPath),
            default => null,
        };

        if ($text === null) {
            return ['error' => "Format file '.$extension' tidak didukung"];
        }

        // Potong teks jika terlalu panjang
        if (strlen($text) > $this->maxChars) {
            $text = substr($text, 0, $this->maxChars) . '...[terpotong]';
        }

        return [
            'filename'   => $filename,
            'extension'  => $extension,
            'characters' => strlen($text),
            'content'    => $text,
        ];
    }

    private function readJson(string $path): string
    {
        $content = file_get_contents($path);
        $data    = json_decode($content, true);
        return json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
    }

    private function readCsv(string $path): string
    {
        $lines = [];
        if (($handle = fopen($path, 'r')) !== false) {
            while (($row = fgetcsv($handle, 1000, ',')) !== false) {
                $lines[] = implode(' | ', $row);
            }
            fclose($handle);
        }
        return implode("\n", $lines);
    }

    private function readPdf(string $path): string
    {
        if (!class_exists('\Smalot\PdfParser\Parser')) {
            return '[Error: Library smalot/pdfparser belum diinstal. Jalankan: composer require smalot/pdfparser]';
        }
        $parser   = new \Smalot\PdfParser\Parser();
        $pdf      = $parser->parseFile($path);
        return $pdf->getText();
    }

    private function readDocx(string $path): string
    {
        if (!class_exists('\PhpOffice\PhpWord\IOFactory')) {
            return '[Error: Library phpoffice/phpword belum diinstal.]';
        }
        $phpWord  = \PhpOffice\PhpWord\IOFactory::load($path);
        $sections = $phpWord->getSections();
        $text     = '';
        foreach ($sections as $section) {
            foreach ($section->getElements() as $element) {
                if (method_exists($element, 'getText')) {
                    $text .= $element->getText() . "\n";
                }
            }
        }
        return $text;
    }
}

Poin Kunci Bab 13

Tool pembaca file membuka kemampuan AI Agent yang sangat kuat — user bisa meng-upload dokumen dan agent akan memahami isinya. Pastikan validasi keamanan diimplementasikan dengan ketat sebelum deploy ke production.