Blogărie este directorul comunității de bloguri din România.
  • PHP 51%
  • CSS 17.5%
  • HTML 16.7%
  • JavaScript 12.7%
  • Shell 1.5%
  • Other 0.6%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-08-04 20:53:14 +03:00
assets adaugare blogarie 2026-08-04 20:53:14 +03:00
data adaugare blogarie 2026-08-04 20:53:14 +03:00
deploy adaugare blogarie 2026-08-04 20:53:14 +03:00
docker adaugare blogarie 2026-08-04 20:53:14 +03:00
includes adaugare blogarie 2026-08-04 20:53:14 +03:00
404.html adaugare blogarie 2026-08-04 20:53:14 +03:00
about.html adaugare blogarie 2026-08-04 20:53:14 +03:00
admin.php adaugare blogarie 2026-08-04 20:53:14 +03:00
aggregated-feed.php adaugare blogarie 2026-08-04 20:53:14 +03:00
api.php adaugare blogarie 2026-08-04 20:53:14 +03:00
apple-touch-icon.png adaugare blogarie 2026-08-04 20:53:14 +03:00
backup-data.php adaugare blogarie 2026-08-04 20:53:14 +03:00
badge.svg adaugare blogarie 2026-08-04 20:53:14 +03:00
blog.php adaugare blogarie 2026-08-04 20:53:14 +03:00
Caddyfile adaugare blogarie 2026-08-04 20:53:14 +03:00
cron-scan.php adaugare blogarie 2026-08-04 20:53:14 +03:00
DEPLOY-DOCKER.md adaugare blogarie 2026-08-04 20:53:14 +03:00
docker-compose.yml adaugare blogarie 2026-08-04 20:53:14 +03:00
Dockerfile adaugare blogarie 2026-08-04 20:53:14 +03:00
favicon.ico adaugare blogarie 2026-08-04 20:53:14 +03:00
feed.atom.php adaugare blogarie 2026-08-04 20:53:14 +03:00
feed.json.php adaugare blogarie 2026-08-04 20:53:14 +03:00
feed.xml.php adaugare blogarie 2026-08-04 20:53:14 +03:00
index.html adaugare blogarie 2026-08-04 20:53:14 +03:00
latest.php adaugare blogarie 2026-08-04 20:53:14 +03:00
LICENSE adaugare blogarie 2026-08-04 20:53:14 +03:00
og-image.png adaugare blogarie 2026-08-04 20:53:14 +03:00
opml.php adaugare blogarie 2026-08-04 20:53:14 +03:00
privacy.html adaugare blogarie 2026-08-04 20:53:14 +03:00
random.php adaugare blogarie 2026-08-04 20:53:14 +03:00
README.md adaugare blogarie 2026-08-04 20:53:14 +03:00
refresh-articles.php adaugare blogarie 2026-08-04 20:53:14 +03:00
robots.txt adaugare blogarie 2026-08-04 20:53:14 +03:00
send-queued-mail.php adaugare blogarie 2026-08-04 20:53:14 +03:00
set-password.php adaugare blogarie 2026-08-04 20:53:14 +03:00
sitemap.php adaugare blogarie 2026-08-04 20:53:14 +03:00
submit.html adaugare blogarie 2026-08-04 20:53:14 +03:00

Blogărie

Directorul comunității de bloguri românești. Oricine are un blog scris în limba română îl poate trimite - sistemul verifică automat dacă blogul pare a fi în română și îl aprobă instant; dacă nu e sigur, blogul intră într-o coadă de aprobare manuală.

Construit cu PHP, JavaScript vanilla și HTML/CSS. Fără framework-uri, fără baze de date - doar fișiere JSON simple, pregătit să susțină 1000+ bloguri.

Live: blogarie.thinkroot.xyz


Funcționalități

  • Aprobare exclusiv manuală - toate trimiterile publice intră într-o coadă de verificare, analizată de un administrator. Nicio combinație de semnale tehnice (limbă, flux RSS etc.) nu poate garanta că un site e chiar un blog, nu doar un site oarecare în limba română.
  • Semnale orientative - serverul calculează automat un scor de limbă română și detectează fluxul RSS/Atom, afișate adminului ca ajutor la triaj rapid - nu decid singure aprobarea.
  • Categorii - fiecare blog poate avea până la 3 categorii din cele 19 disponibile, alese la trimitere - esențial pentru navigare ușoară cu mii de bloguri.
  • Descrieri de bloguri - preluate automat din <meta name="description"> la trimitere.
  • Detecție flux - detectează automat fluxul RSS/Atom al blogului și afișează o iconiță pe fiecare card.
  • Favicon-uri - afișează favicon-ul fiecărui blog prin Google Favicon Service.
  • Ordine aleatorie - lista de bloguri e amestecată la fiecare încărcare a paginii (plus sortare A-Z și „cele mai noi”).
  • Căutare - căutare pe partea de client, după nume sau adresă.
  • Filtrare pe categorii - chip-uri de categorie cu numărul de bloguri din fiecare.
  • Paginare - 21 bloguri pe pagină.
  • RSS, Atom și JSON Feed - abonează-te la director ca să urmărești blogurile noi.
  • Export OPML - importă toate fluxurile blogurilor dintr-o dată în orice cititor RSS.
  • Prompt de distribuire - după aprobare, distribuie anunțul pe Mastodon sau Bluesky.
  • Panou de administrare - protejat prin parolă, pentru aprobarea cozii de așteptare, adăugare, editare și eliminare bloguri.
  • Scanare săptămânală - job cron automat verifică toate blogurile și semnalează cele care nu mai sunt accesibile.
  • Limitare de rată - maxim 3 trimiteri pe IP pe oră (ocolită pentru admin).
  • Pregătit pentru SEO - meta tag-uri, Open Graph, Twitter Card, date structurate JSON-LD, sitemap dinamic (inclusiv paginile de profil ale blogurilor).
  • Securizat - protecție CSRF, prevenire SSRF, honeypot, headere de securitate prin .htaccess.
  • Open source - licență MIT.

Structura fișierelor

blogarie/
├── index.html              # Pagina principală (director)
├── submit.html              # Formular de trimitere blog
├── about.html                # Pagina „Despre”
├── privacy.html               # Politica de confidențialitate
├── api.php                     # API REST - toate endpoint-urile
├── admin.php                    # Panou admin protejat prin parolă
├── sitemap.php                   # Sitemap XML dinamic
├── feed.xml.php                   # Flux RSS 2.0 al directorului
├── feed.atom.php                   # Flux Atom al directorului
├── feed.json.php                    # JSON Feed al directorului
├── aggregated-feed.php                # Flux RSS agregat cu articole recente
├── opml.php                            # Export OPML al tuturor fluxurilor
├── latest.php                           # Pagina „Articole recente”
├── blog.php                              # Pagina de profil a unui blog
├── random.php                             # Redirect către un articol aleatoriu
├── cron-scan.php                           # Script cron săptămânal de scanare
├── refresh-articles.php                     # Script cron - reîmprospătare cache articole (la 10 min)
├── backup-data.php                            # Script cron - backup zilnic data/*.json (retenție 30 zile)
├── send-queued-mail.php                       # Script cron - trimite notificările puse în coadă (la 60s)
├── set-password.php                         # Utilitar CLI pentru hash-ul parolei admin
├── includes/
│   ├── categories.php                        # Sursă unică pentru lista de categorii
│   ├── helpers.php                           # esc(), relativeTime(), addRef(), faviconUrl()
│   └── mailer.php                            # Client SMTP + notificări prin email
├── robots.txt                                # Directive pentru motoarele de căutare
├── .htaccess                                  # Config Apache - securitate, cache, gzip
├── favicon.ico                                 # Favicon multi-mărime (16/32/48px)
├── apple-touch-icon.png                         # Iconiță ecran acasă iOS
├── og-image.png                                  # Imagine Open Graph
├── badge.svg                                      # Insignă „Listat pe Blogărie”
├── Dockerfile                                       # Imaginea PHP + Apache
├── docker-compose.yml                                # Orchestrare app + caddy + cron
├── Caddyfile                                          # Reverse proxy, HTTPS automat
├── .env.example                                        # Șablon variabile de mediu Docker
├── docker/
│   ├── entrypoint.sh        # Înlocuiește domeniul la pornirea containerului
│   └── cron-loop.sh         # Bucla de scanare/reîmprospătare/backup (container cron)
├── DEPLOY-DOCKER.md         # Ghid de publicare cu Docker (recomandat)
├── DEPLOY-VPS.md            # Ghid de publicare directă pe VPS, fără Docker
├── LICENSE
├── README.md
├── assets/
│   ├── css/
│   │   ├── main.css        # Stiluri site public
│   │   ├── blog.css        # Stiluri pagină profil blog
│   │   ├── latest.css      # Stiluri pagină articole recente
│   │   └── admin.css       # Stiluri panou admin
│   ├── js/
│   │   ├── main.js         # JavaScript site public
│   │   └── admin.js        # JavaScript panou admin
│   └── images/
│       ├── favicon.svg
│       ├── favicon-16.png / favicon-32.png / favicon-48.png / favicon-180.png
│       └── og-image.svg / og-image.png
└── data/
    ├── .htaccess           # Interzice accesul web la acest director
    ├── blogs.json          # Baza de date a blogurilor
    ├── articles.json       # Cache articole agregate din fluxuri
    ├── rate.json           # Urmărire limitare de rată (gestionat automat)
    ├── mail-settings.json  # Setări SMTP (create din panou, tab Setări)
    ├── mail-queue.json     # Coadă notificări de trimis (gestionată automat)
    └── backups/AAAA-LL-ZZ/ # Backup-uri zilnice (create automat, retenție 30 zile)

Cerințe

Cu Docker (recomandat): doar Docker și Docker Compose pe server - restul (PHP, Apache, extensii, certificat HTTPS) e gestionat automat de containere. Vezi DEPLOY-DOCKER.md.

Fără Docker:

  • PHP 7.4 sau mai nou
  • Apache cu mod_rewrite, mod_headers, mod_deflate, mod_expires
  • Extensia cURL activată în PHP
  • Permisiuni de scriere pe data/blogs.json și data/rate.json

Publicare

Metoda recomandată - Docker (VPS sau bare metal): vezi DEPLOY-DOCKER.md. Totul rulează în containere (Apache+PHP, Caddy pentru HTTPS automat, scanare săptămânală) - nu se instalează nimic direct pe server.

Alternativă - instalare directă pe hosting sau VPS, fără Docker: vezi mai jos pentru hosting partajat (cPanel) sau DEPLOY-VPS.md pentru un VPS Ubuntu/Debian cu Apache instalat manual.

Publicare pe hosting partajat

  1. Încarcă toate fișierele în public_html/ (sau un subdirector).

  2. Setează permisiunile fișierelor:

    data/blogs.json   → 644
    data/rate.json    → 644
    data/             → 755
    
  3. Setează parola de admin - rulează această comandă prin SSH sau un terminal PHP:

    php set-password.php
    

    Copiază hash-ul generat și înlocuiește-l în admin.php, ca valoare a ADMIN_PASSWORD_HASH. Parola implicită din fișier este schimba-parola-acum - schimb-o obligatoriu înainte de a publica site-ul.

  4. Setează o cheie secretă pentru endpoint-ul de scanare - deschide api.php și modifică:

    define('SCAN_SECRET', 'CHANGE_THIS_TO_A_RANDOM_SECRET_KEY');
    
  5. Dacă domeniul tău nu este blogarie.thinkroot.xyz, înlocuiește toate aparițiile https://blogarie.thinkroot.xyz cu domeniul tău în:

    • index.html, submit.html, about.html, privacy.html, blog.php, latest.php - URL canonic, tag-uri OG
    • sitemap.php, feed.xml.php, feed.atom.php, feed.json.php, aggregated-feed.php, opml.php - constanta BASE_URL
    • robots.txt - directiva Sitemap
    • assets/images/og-image.svg - domeniul afișat în imagine (apoi regenerează og-image.png)
    • adresele de contact root@thinkroot.xyz
  6. Configurează job-ul cron săptămânal în cPanel → Cron Jobs:

    Minut: 0 | Oră: 8 | Zi: * | Lună: * | Zi săptămână: 1
    Comandă: /usr/local/bin/php /home/UTILIZATORUL_TAU/public_html/blogarie/cron-scan.php
    
  7. Verifică funcționarea accesând:

    https://DOMENIUL_TAU/api.php?action=ping
    

    Toate valorile trebuie să fie true.


Endpoint-uri API

Toate endpoint-urile sunt servite de api.php.

Metodă Endpoint Autentificare Descriere
GET ?action=list - Returnează toate blogurile aprobate, în format JSON
GET ?action=categories - Returnează lista de categorii disponibile
GET ?action=token - Returnează un token CSRF pentru formularul de trimitere
GET ?action=ping - Endpoint de diagnosticare - verifică PHP, cURL, permisiuni fișiere
GET ?action=scan Sesiune admin sau cheie secretă Scanează toate blogurile și semnalează cele inaccesibile
POST ?action=submit Token CSRF Trimitere publică de blog, cu limitare de rată
POST ?action=admin-submit Sesiune admin Adaugă un blog, aprobat direct (necesită acces la site, fără limită de rată)
POST ?action=admin-force-add Sesiune admin Adaugă un blog fără să necesite acces la site, aprobat direct
POST ?action=admin-approve Sesiune admin Aprobă un blog aflat în așteptare sau inaccesibil
POST ?action=admin-edit Sesiune admin Editează numele, adresa, categoria sau descrierea unui blog
POST ?action=admin-delete Sesiune admin Elimină un blog după ID

Aprobarea blogurilor

Toate trimiterile publice merg la verificare manuală (status pending) - nu există aprobare automată. Motivul: nicio combinație de semnale tehnice nu poate garanta că un site e chiar un blog personal - site-uri de firmă, unelte sau publicații de știri pot avea la fel de bine conținut în limba română și chiar un flux RSS.

La trimitere, serverul calculează totuși un scor orientativ de limbă română (funcția detectRomanian() din api.php) și detectează fluxul RSS/Atom - ambele sunt afișate în panoul de admin, în coloana „Semnale”, ca ajutor la triaj rapid al cozii de așteptare. Nu decid singure nimic.

Foarte multe bloguri românești sunt scrise fără diacritice (ă, â, î, ș, ț) - din obiceiuri vechi, teme netraduse sau taste. Din acest motiv, scorul de limbă nu se bazează pe diacritice: textul paginii este normalizat (diacriticele sunt eliminate) înainte de a căuta sintagme și cuvinte specifice limbii, deci funcționează la fel de bine cu sau fără ele.

Semnal Puncte Sursă
Atribut lang="ro" pe <html> 12 HTML-ul paginii principale
<meta http-equiv="content-language" content="ro"> 8 HTML-ul paginii principale
<meta property="og:locale" content="ro_RO"> 5 HTML-ul paginii principale (setat automat de multe pluginuri SEO)
Domeniu .ro 2 Adresa blogului
Sintagme distinctive (ex: „toate drepturile rezervate”, „citește mai mult”, max 4 găsite) 3 fiecare Text vizibil, normalizat fără diacritice
Cuvinte distinctive limbii române (max 10 găsite) 1 fiecare Text vizibil, normalizat fără diacritice
Prezența efectivă a diacriticelor - bonus, nu obligatoriu 2-4 Text vizibil de pe pagină

Blogurile adăugate de admin din panou (?action=admin-submit) sunt aprobate direct - se presupune că adminul deja le-a verificat înainte să le adauge. ?action=admin-force-add rămâne util pentru site-uri care blochează accesul automat al serverului (fetch eșuează), unde nici verificarea minimă nu se poate face.


Categorii

Fiecare blog poate avea până la 3 categorii, alese la trimitere:

Tehnologie · Lifestyle · Călătorii · Mâncare & Rețete · Sănătate & Fitness · Familie & Părinți · Educație · Cultură & Arte · Modă & Frumusețe · Business & Antreprenoriat · Finanțe personale · Auto & Moto · Sport · Gaming · Fotografie · Cărți & Literatură · Muzică · Jurnal personal · Altele

Lista de categorii este definită în api.php (funcția categories()) și este duplicată în submit.html (elementul <select>) și în admin.php/admin.js. Dacă modifici lista, actualizeaz-o în toate aceste locuri.


Panoul de administrare

Accesează panoul de admin la /admin, organizat în cinci pagini (taburi): Panou (statistici + coada de aprobat), Bloguri aprobate, Bloguri inaccesibile, Coș de gunoi și Setări. După autentificare poți:

  • Aproba blogurile aflate în coada de așteptare (toate trimiterile publice) sau marcate inaccesibile de scanare - coloana „Semnale” arată scorul de limbă și dacă are flux RSS, ca ajutor la decizie
  • Adăuga un blog, aprobat direct (fără limită de rată)
  • Adăuga forțat un blog fără să necesite acces la site (pentru cele care blochează accesul automat al serverului)
  • Edita numele, adresa, categoria sau descrierea unui blog, direct din tabel
  • Verifica acum un singur blog (fără să aștepți scanarea completă a tuturor)
  • Elimina un blog - nu se șterge imediat, ci ajunge în coșul de gunoi (recuperabil 30 de zile)
  • Restaura sau șterge definitiv un blog din coșul de gunoi
  • Căuta și pagina în orice listă de bloguri, după nume, adresă sau descriere
  • Scana manual toate blogurile prin butonul de scanare - marchează blogurile inaccesibile
  • Configura notificări prin email (tab Setări) și descărca manual un backup al datelor

Scanare automată

Job-ul cron săptămânal (cron-scan.php) verifică fiecare blog aprobat din director și:

  • Marchează blogurile inaccesibile ca needs_review
  • Restaurează blogurile la approved dacă redevin accesibile
  • Nu modifică statusul blogurilor aflate în așteptare de aprobare manuală (pending)
  • Trimite un email de alertă dacă au fost marcate ca inaccesibile bloguri noi (dacă notificările sunt activate)
  • Șterge definitiv blogurile din coșul de gunoi mai vechi de 30 de zile

Blogurile inaccesibile apar într-o listă separată în panoul de admin („Bloguri inaccesibile”), cu data la care au fost marcate astfel. Nu mai apar în directorul public cât timp au acest status și nu sunt șterse automat - un admin le poate marca manual drept funcționale sau le poate elimina dacă sunt sigur abandonate.

Separat, refresh-articles.php rulează la fiecare 10 minute și reîmprospătează cache-ul de articole (data/articles.json) folosit de pagina „Articole recente” - latest.php doar citește acest cache, nu-l reîmprospătează el însuși la cerere (ar bloca vizitatorul ghinionist până se preiau toate fluxurile RSS, secvențial). Fiecare blog contribuie cu cel mult 10 articole (MAX_PER_BLOG) - un plafon doar pe total, fără plafon per blog, lăsa bloguri întregi fără nicio reprezentare în listă și în filtrele pe categorie. Dacă majoritatea fluxurilor eșuează la un ciclu (posibilă problemă de rețea a serverului), trimite un email de alertă (cel mult unul la 6 ore).

backup-data.php rulează zilnic la 03:00 și copiază data/*.json în data/backups/AAAA-LL-ZZ/, cu retenție de 30 de zile - singura plasă de siguranță reală pe un VPS fără bază de date cu backup gestionat. Poți descărca și manual o copie curentă din tab-ul Setări.

Notificări prin email

Din tab-ul Setări, poți configura un server SMTP (gazdă, port, criptare, utilizator/parolă opționale, adresă expeditor și destinatar) pentru a primi un email când:

  • cineva trimite un blog nou prin formularul public (nu și când adaugi tu un blog direct din panou - deja l-ai verificat)
  • scanarea săptămânală semnalează bloguri noi ca inaccesibile
  • reîmprospătarea articolelor eșuează pe scară largă (probabil o problemă de rețea, nu bloguri individuale picate)

Setările sunt salvate în data/mail-settings.json (protejat de .htaccess, la fel ca restul directorului data/), nu în .env - se pot schimba fără redeploy. Clientul SMTP e scris de mână (fără dependențe externe), suportă STARTTLS, SSL implicit și AUTH LOGIN.

Notificarea de la trimiterea publică e pusă într-o coadă (data/mail-queue.json), nu trimisă direct din cererea vizitatorului - un handshake SMTP poate dura secunde bune sau poate eșua complet, iar asta n-are nicio legătură cu vizitatorul care doar își trimite blogul. Coada e golită efectiv în fundal, de send-queued-mail.php, rulat la fiecare tick (60s) de docker/cron-loop.sh; elementele care eșuează (ex: SMTP temporar indisponibil) rămân pentru reîncercare, iar cele mai vechi de 24h sunt abandonate.


Fluxuri

Directorul oferă trei formate de flux, actualizate automat pe măsură ce blogurile sunt adăugate:

Format Adresă
RSS 2.0 /feed.xml.php
Atom /feed.atom.php
JSON Feed /feed.json.php
Articole recente (RSS agregat) /aggregated-feed.php
Articole recente, filtrat pe categorie /aggregated-feed.php?cat=tehnologie (slug-ul categoriei)
Export OPML /opml.php

Securitate

  • Protecție CSRF - toate trimiterile publice de formulare necesită un token legat de sesiune
  • Prevenire SSRF - adresele trimise sunt verificate față de intervale de IP private înainte ca serverul să le acceseze
  • Honeypot - un câmp invizibil prinde trimiterile automate de tip bot
  • Limitare de rată - trimiterile publice sunt limitate la 3 pe IP pe oră
  • Headere de securitate - X-Frame-Options, X-Content-Type-Options, Content-Security-Policy, Referrer-Policy, Permissions-Policy
  • Hashing IP - adresele IP ale celor care trimit bloguri sunt stocate ca hash-uri SHA-256, niciodată în clar
  • Scrieri atomice - blogs.json este scris prin fișier temporar + redenumire, pentru a preveni corupția datelor
  • Director de date protejat - data/ are propriul .htaccess care interzice orice acces web

Scalare la 1000+ bloguri

Proiectul folosește fișiere JSON plate, nu o bază de date - alegere deliberată, pentru simplitate. La 1000-5000 bloguri, blogs.json rămâne de ordinul sutelor de KB, iar ?action=list este cache-uit automat pe server (invalidat quando blogs.json se modifică), deci performanța rămâne bună. Filtrarea pe categorii, căutarea și sortarea au loc pe partea de client, după o singură încărcare a listei complete.

Dacă directorul depășește semnificativ 5000-10000 bloguri, ia în calcul paginarea la nivel de server pentru endpoint-ul ?action=list - arhitectura curentă e suficientă pentru obiectivul de 1000+ bloguri, dar nu e nelimitată.


Cum poți contribui

Proiectul este open source, sub licența MIT. Pentru a contribui:

  1. Fă un fork al proiectului
  2. Creează o ramură: git checkout -b feature/functia-ta
  3. Fă commit la modificări: git commit -m 'Adaugă funcția ta'
  4. Trimite ramura: git push origin feature/functia-ta
  5. Deschide un pull request

Păstrează spiritul proiectului: fără framework-uri, fără baze de date, dependențe minime.


Licență

Licență MIT - vezi LICENSE pentru textul complet.


Construit cu

Acest proiect a fost construit cu Claude AI de la Anthropic, pornind de la structura proiectului Pure Blog Discover.