Documentation πŸ‡ΊπŸ‡Έ

sansCMS Documentation

Welcome to the complete documentation for sansCMS, a simple and lightweight content management system based on Markdown files.

πŸš€ Overview

sansCMS is a lightweight, fast, database-free Content Management System. It uses Markdown files to store content and features a high-performance caching system with customizable TTLs.

Key Features

  • βœ… Database-free: Uses only Markdown files
  • ⚑ Smart caching system with customizable TTLs
  • πŸ“Š Visit statistics with unique IP tracking
  • 🎨 Multiple themes with built-in selector
  • πŸ”’ Private pages with password protection
  • πŸ” SEO optimized (sitemap, RSS, meta tags)
  • πŸ“± Responsive based on Pico CSS
  • πŸ“§ Built-in contact form
  • πŸš€ High performance with compression and minification

Architecture

sansCMS/
β”œβ”€β”€ cache/              # System cache (protected)
β”‚   β”œβ”€β”€ markdown/       # Markdown rendering cache
β”‚   β”œβ”€β”€ pages/          # Complete pages cache
β”‚   └── stats/          # Statistics cache
β”œβ”€β”€ config/             # Configuration files
β”‚   └── site.json       # Main configuration
β”œβ”€β”€ libs/               # Third-party libraries
β”‚   └── Parsedown.php   # Markdown parser
β”œβ”€β”€ logs/               # Logs and statistics
β”‚   └── stats.json      # Tracking data
β”œβ”€β”€ pages/              # Markdown content
β”‚   β”œβ”€β”€ 1-home.md       # Homepage
β”‚   β”œβ”€β”€ 2-contact.md    # Contact page
β”‚   └── *.md            # Other pages/posts
β”œβ”€β”€ src/                # PHP source code
β”‚   β”œβ”€β”€ CacheManager.php          # Cache management
β”‚   β”œβ”€β”€ ConfigLoader.php          # Configuration loader
β”‚   β”œβ”€β”€ ContactFormHandler.php    # Contact form handler
β”‚   β”œβ”€β”€ MarkdownParser.php        # Markdown parser with cache
β”‚   β”œβ”€β”€ OutputOptimizer.php       # HTML output optimization
β”‚   β”œβ”€β”€ Page.php                  # Page class
β”‚   β”œβ”€β”€ Router.php                # Request routing
β”‚   β”œβ”€β”€ sansCMS.php               # Main class
β”‚   └── StatsTracker.php          # Statistics tracking
β”œβ”€β”€ themes/             # Visual themes
β”‚   └── pico/           # Default theme
β”œβ”€β”€ index.php           # Entry point
└── .htaccess           # Apache configuration

Installation

  1. Download the project to your web server
  2. Check that PHP 7.4+ is installed
  3. Configure the web server (Apache or Nginx)
  4. Create the config/site.json file (generated automatically on first run)

Server Configuration

Apache

The .htaccess file is created automatically:

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php [L]
Options -Indexes

Nginx

Configuration generated in nginx-site.conf:

server {
    listen 80;
    server_name localhost;
    root /path/to/sansCMS;
    index index.php;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        include fastcgi_params;
        fastcgi_pass unix:/var/run/php/php-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }

    location ~* \.md$ {
        deny all;
        return 403;
    }
}

Configuration (site.json)

{
  "site": {
    "name": "My Site",
    "description": "My site description",
    "contact_email": "email@example.com",
    "contact_subjects": {
      "general": "General inquiry",
      "support": "Support request",
      "business": "Business inquiry",
      "bug": "Bug report",
      "suggestion": "Feature suggestion"
    }
  },
  "blog": {
    "url": "blog",
    "name": "Blog",
    "description": "Discover our articles"
  },
  "theme": {
    "name": "pico",
    "posts_per_page": 8
  },
  "features": {
    "cache_enabled": true,
    "cache_ttl": {
      "markdown": 3600,    // 1 hour
      "pages": 7200,       // 2 hours
      "stats": 300,        // 5 minutes
      "rss": 3600,         // 1 hour
      "sitemap": 86400     // 24 hours
    },
    "stats_enabled": true,
    "stats_access_enabled": true,
    "session_timeout": 1800,
    "rate_limit_enabled": true
  },
  "performance": {
    "lazy_load_pages": true,
    "compress_output": true,
    "minify_html": false
  },
  "debug": {
    "enabled": false,
    "level": "INFO",
    "log_to_file": true,
    "display_errors": false
  },
  "seo": {
    "meta_keywords": "cms, markdown, blog",
    "robots": "index, follow",
    "rss_enabled": true
  }
}

Markdown File Format

Basic Structure

---
titre: Page Title
description: SEO description
date: 2024-01-15
auteur: Author Name
tags: tag1, tag2, tag3
permalien: my-article
---

Your page content in **Markdown**.

### Level 2 Heading

Your text with [links](https://example.com).

Available Metadata

FieldTypeDescription
titrestringPage/post title
descriptionstringSEO description
datedatePublication date (format: YYYY-MM-DD)
auteurstringAuthor name
tagsstringComma-separated tags
permalienstringCustom URL
privestringPassword hash (bcrypt)
brouillonbooleanHide from publication
cacherbooleanHide from navigation but accessible via URL

Private Page

To create a private page:

---
titre: Private Page
prive: $2y$10$example_bcrypt_hash
---

Generate bcrypt hash in PHP:

echo password_hash('my_password', PASSWORD_BCRYPT);

Automatic Table of Contents

Insert [TOC] or [TOC:Custom Title] in your content:

[TOC:Table of Contents]

### Section 1
Content...

### Section 2
Content...

Caching System

Cache Architecture

The system uses three cache levels:

  1. Markdown Cache: HTML renders of .md files
  2. Pages Cache: Complete pages with templates
  3. Stats Cache: Pre-calculated statistics

Customizable TTLs

Time-to-live (TTL) values are independently configurable:

"cache_ttl": {
  "markdown": 3600,    // Markdown rendering (1h)
  "pages": 7200,       // Complete pages (2h)
  "stats": 300,        // Statistics (5min)
  "rss": 3600,         // RSS feed (1h)
  "sitemap": 86400     // XML sitemap (24h)
}

Cache Management

// Clear all cache
CacheManager::clearAll();

// Clear only Markdown cache
CacheManager::clearMarkdownCache();

// Get cache statistics
$stats = CacheManager::getStats();

// Clean expired files
CacheManager::cleanExpired();

Admin Page

Access /cache-admin (requires debug.enabled: true) to:

  • View cache statistics
  • Selectively clear cache
  • See cached file details

Statistics System

Features

  • Unique views per IP counting
  • Statistics by day/hour
  • Popular pages
  • Weekly reports
  • 5-minute cache for performance

Usage

// Get stats for last 30 days
$stats = StatsTracker::getStats(30);

// Get text report
$report = StatsTracker::getSimpleReport(7);

// Rebuild cache
StatsTracker::rebuildCache();

Data Structure

[
    'total_views' => 1234,
    'pages_count' => 45,
    'recent_days' => [
        '2024-01-15' => 56,
        '2024-01-14' => 42,
        // ...
    ],
    'popular_pages' => [
        '/article' => [
            'title' => 'My Article',
            'total_views' => 234,
            'type' => 'post'
        ]
    ]
]

Routing

Available Routes

RouteDescription
/Homepage
/blogPost list
/blog?page=2Pagination
/blog?tag=phpFilter by tag
/blog?auteur=JohnFilter by author
/blog?q=searchSearch
/sitemapXML sitemap
/rssRSS feed
/statsStatistics
/cache-adminCache admin (debug)
/logoutLogout private pages

Contact Form

Configuration

The form uses the email configured in site.json:

"contact_email": "contact@example.com",
"contact_subjects": {
  "general": "General inquiry",
  "support": "Technical support"
}

Security

  • CSRF protection with tokens
  • Anti-spam honeypot
  • Server-side validation
  • Rate limiting

Customizable Templates

themes/pico/contact/
β”œβ”€β”€ contact-form.php       # Form
β”œβ”€β”€ contact-success.php    # Success message
β”œβ”€β”€ contact-errors.php     # Error display
β”œβ”€β”€ contact-sent.php       # Send confirmation
└── email-contact.php      # HTML email template

Performance Optimization

Output Compression

"compress_output": true  // Enable gzip

HTML Minification

"minify_html": true  // Remove unnecessary spaces

OPcache

Enable OPcache in php.ini:

opcache.enable=1
opcache.memory_consumption=128
opcache.max_accelerated_files=10000
opcache.revalidate_freq=2

SEO

Built-in Features

  • βœ… Automatic XML sitemap
  • βœ… Complete RSS feed
  • βœ… Open Graph meta tags
  • βœ… Twitter Cards
  • βœ… Canonical URLs
  • βœ… SEO-friendly pagination
  • βœ… Structured data

Optimization

---
titre: My SEO-optimized article
description: Unique 150-160 character description
tags: keyword1, keyword2
---

Security

Folder Protection

All sensitive folders are automatically protected:

  • cache/ β†’ Access denied
  • config/ β†’ Access denied
  • logs/ β†’ Access denied
  • src/ β†’ Access denied
  • pages/ β†’ .md files not accessible

Sessions

"session_timeout": 1800  // 30 minutes

Rate Limiting

Protection against form abuse.

Debugging

Enable Debug Mode

"debug": {
  "enabled": true,
  "level": "INFO",
  "display_errors": true
}

Displayed Metrics

  • ⏱️ Execution time
  • πŸ’Ύ Memory used
  • πŸ“Š Cache statistics
  • πŸ”§ Active configuration
  • ⚑ OPcache status

API and Helpers

ConfigLoader

// Get a value
$value = ConfigLoader::get('site.name');
$value = ConfigLoader::get('missing.key', 'default');

// Check a feature
if (ConfigLoader::isFeatureEnabled('cache')) {
    // Cache enabled
}

// Get specific TTL
$ttl = ConfigLoader::getCacheTTL('markdown');

CacheManager

// Paths
$cache_dir = CacheManager::getCacheDir();
$md_cache = CacheManager::getMarkdownCachePath();

// Statistics
$stats = CacheManager::getStats();
$size = CacheManager::getTotalSize();

// Cleanup
CacheManager::clearAll();
CacheManager::clearMarkdownCache();
CacheManager::cleanExpired(3600);

// Protection
$checks = CacheManager::checkProtection();

MarkdownParser

// Parse with cache
$result = MarkdownParser::parse($content, $source_file);
// ['metadata' => [], 'content' => '...']

// Statistics
$stats = MarkdownParser::getCacheStats();
$size = MarkdownParser::getCacheSize();
$details = MarkdownParser::getCacheDetails();

// Cleanup
MarkdownParser::clearCache();

Migration and Maintenance

Backup

Files to backup regularly:

config/site.json
pages/*.md
logs/stats.json

Restoration

  1. Restore files
  2. Cache will be regenerated automatically

Update

  1. Backup config/ and pages/
  2. Replace system files
  3. Check config/site.json for new options
  4. Clear cache: /cache-admin

Troubleshooting

Cache Not Working

  1. Check cache_enabled: true in site.json
  2. Check cache/ folder permissions
  3. Check logs in debug mode

Statistics Not Displaying

  1. Check stats_enabled: true
  2. Check logs/ permissions
  3. Check stats_access_enabled for /stats URL

Error 500

  1. Enable debug mode
  2. Check PHP logs
  3. Check folder permissions
  4. Check site.json syntax

Private Pages Not Working

  1. Verify bcrypt hash is correct
  2. Verify PHP sessions are working
  3. Check session_timeout in config

License

  • See LICENSE file for details

Support

For support and questions, please visit the project repository or contact the development team.


Version: 1.0.0-stable
Last Updated: November 2024