SplashContent is a complete, production-ready multi-tenant SaaS platform for AI-powered content generation built with PHP 7.0+ and MySQL. Designed for marketers, copywriters, and agencies to generate high-quality content using customizable templates.
- ✅ Multi-tenant architecture with complete data isolation
- ✅ AI content generation with 11+ built-in templates
- ✅ Custom template creation for enterprise plans
- ✅ Brand voice profiles for consistent messaging
- ✅ Project management to organize content by client/campaign
- ✅ Team collaboration with role-based access control
- ✅ Usage tracking & quota enforcement
- ✅ Subscription management with multiple plans
- ✅ RESTful API for external integrations
- ✅ File uploads for brand assets
- ✅ Content history with search and filtering
- Blog Post Ideas
- Blog Post Outline
- Blog Section/Paragraph
- Product Description
- Twitter/X Posts
- Facebook Posts
- Instagram Captions
- Google Ad Copy
- Facebook Ad Copy
- Email Subject Lines
- Cold Email Outreach
- Password hashing with
password_hash() - CSRF protection on all forms
- SQL injection prevention via PDO prepared statements
- Input validation and sanitization
- File upload security with type/size validation
- Directory traversal prevention
- Secure session management
- PHP: 7.0 or higher (7.0 - 8.x compatible)
- MySQL: 5.7+ or MariaDB 10.2+
- Web Server: Apache 2.4+ (with mod_rewrite) or Nginx
- PHP Extensions:
- PDO
- pdo_mysql
- mbstring
- json
- fileinfo
git clone <repository-url> SplashContent
cd SplashContentCopy the example environment file:
cp .env.example .envEdit .env and configure your database credentials:
APP_URL=http://localhost
APP_DEBUG=true
DB_HOST=localhost
DB_NAME=splashcontent
DB_USER=root
DB_PASS=your_password
APP_TIMEZONE=UTCCreate the database:
mysql -u root -p -e "CREATE DATABASE splashcontent CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"Import the schema and seed data:
mysql -u root -p splashcontent < database.sqlThis will create all tables and insert:
- 4 subscription plans (Free Trial, Starter, Professional, Enterprise)
- 1 platform admin account
- 2 demo tenant accounts with users
- 11 global content templates
- Sample generations, projects, and usage data
Ensure the web server can write to the upload directory:
mkdir -p storage/uploads
chmod 755 storage/uploads
chown -R www-data:www-data storage/uploadsThe .htaccess file is already included in /public. Ensure mod_rewrite is enabled:
sudo a2enmod rewrite
sudo systemctl restart apache2Configure your Apache virtual host to point to the public directory:
<VirtualHost *:80>
ServerName splashcontent.local
DocumentRoot /path/to/SplashContent/public
<Directory /path/to/SplashContent/public>
AllowOverride All
Require all granted
</Directory>
ErrorLog ${APACHE_LOG_DIR}/splashcontent_error.log
CustomLog ${APACHE_LOG_DIR}/splashcontent_access.log combined
</VirtualHost>server {
listen 80;
server_name splashcontent.local;
root /path/to/SplashContent/public;
index index.php;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
}
location ~ /\.ht {
deny all;
}
}Navigate to http://localhost (or your configured domain).
After importing database.sql, you'll have access to these demo accounts:
- Email:
admin@splashcontent.com - Password:
admin123 - Access: Full platform administration
- Tenant Admin:
- Email:
john@creativemarketing.example - Password:
password123
- Email:
- Regular Users:
- Email:
sarah@creativemarketing.example/ Password:password123 - Email:
mike@creativemarketing.example/ Password:password123
- Email:
- Tenant Admin:
- Email:
emma@ecommercebrands.example - Password:
password123
- Email:
- Regular User:
- Email:
david@ecommercebrands.example/ Password:password123
- Email:
SplashContent provides a RESTful API for external integrations. All API requests require an X-API-KEY header.
Include your API key in the request header:
X-API-KEY: your_api_key_here
To generate an API key:
- Login as tenant admin
- Navigate to Settings > API Keys
- Click Generate New API Key
- Save the key securely (it's only shown once)
Endpoint: POST /api/generate
Description: Generate content using a template.
Request Headers:
Content-Type: application/json
X-API-KEY: your_api_key
Request Body:
{
"template_key": "blog_ideas",
"input_parameters": {
"topic": "AI and Machine Learning",
"keywords": "automation, productivity, AI",
"audience": "tech professionals"
},
"language": "en",
"tone": "professional"
}Response (201 Created):
{
"success": true,
"generation_id": 123,
"generated_text": "1. \"How AI is Revolutionizing...\"\n2. \"Top 10 Machine Learning...\"",
"word_count": 85,
"template": "Blog Post Ideas"
}Error Response (403 Forbidden - Quota Exceeded):
{
"error": "Quota exceeded: generations limit reached",
"quota": {
"exceeded": true,
"limit_type": "generations",
"current": 500,
"limit": 500
}
}Endpoint: GET /api/generations/{id}
Description: Retrieve a specific generation.
Request Headers:
X-API-KEY: your_api_key
Response (200 OK):
{
"id": 123,
"template": {
"id": 1,
"name": "Blog Post Ideas",
"key": "blog_ideas"
},
"input_data": {
"topic": "AI and Machine Learning",
"keywords": "automation, productivity, AI"
},
"generated_text": "1. \"How AI is Revolutionizing...\"",
"word_count": 85,
"language": "en",
"tone": "professional",
"status": "completed",
"created_at": "2024-01-15 10:30:00"
}Endpoint: GET /api/templates
Description: Get all available templates for your tenant.
Request Headers:
X-API-KEY: your_api_key
Response (200 OK):
{
"templates": [
{
"id": 1,
"key": "blog_ideas",
"name": "Blog Post Ideas",
"category": "Blog",
"description": "Generate creative blog post ideas",
"input_schema": {
"fields": [
{
"key": "topic",
"label": "Topic",
"type": "text",
"required": true
}
]
},
"output_type": "short"
}
],
"count": 11
}Endpoint: GET /api/usage
Description: Get current usage and quota information.
Request Headers:
X-API-KEY: your_api_key
Response (200 OK):
{
"current_period": {
"start": "2024-01-01",
"end": "2024-01-31"
},
"usage": {
"generations": 145,
"words": 28500,
"api_calls": 67
},
"limits": {
"generations": 2000,
"words": 500000
},
"plan": {
"name": "Professional",
"status": "active"
}
}The platform currently uses dummy AI content generation. To integrate a real AI provider (OpenAI, Anthropic Claude, etc.):
-
Edit
/app/helpers/AiService.php -
Add your API key to
.env:AI_API_KEY=your_openai_api_key_here AI_MODEL=gpt-3.5-turbo
-
Uncomment and implement the
callRealAiApi()method:
private function callRealAiApi($template, $parameters, $options)
{
$prompt = $this->buildPrompt($template, $parameters, $options);
$ch = curl_init('https://api.openai.com/v1/chat/completions');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'Authorization: Bearer ' . $this->apiKey
]);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
'model' => $this->model,
'messages' => [
['role' => 'system', 'content' => 'You are a professional content writer.'],
['role' => 'user', 'content' => $prompt]
],
'temperature' => 0.7
]));
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);
return $data['choices'][0]['message']['content'] ?? 'Error generating content';
}- For Anthropic Claude, adjust the API endpoint and request format accordingly.
php tests/functional_tests.phpThis will test:
- Database connectivity
- Model operations (User, Tenant, Template, Generation)
- AI service functionality
- Validation helpers
- Multi-tenant isolation
- Subscription and usage tracking
- User can register new account
- User can login with correct credentials
- Login fails with incorrect credentials
- User can logout
- User can select a template
- Generation form displays correct input fields
- Content generates successfully
- Generated content is stored in database
- Usage quota is incremented
- Quota enforcement blocks generation when limit reached
- User from Tenant A cannot access Tenant B's data
- Generation queries are filtered by tenant_id
- Templates are scoped correctly (global + tenant custom)
- Subscription limits are enforced
- Usage percentage displays correctly
- Plan upgrades work correctly
- API authentication works with valid key
- API rejects requests without valid key
- Generate content via API works
- Get generation by ID works
- List templates via API works
- Usage endpoint returns correct data
-
Environment Configuration:
APP_DEBUG=false
-
Database Security:
- Use strong database passwords
- Create dedicated database user with minimal privileges
- Enable MySQL SSL connections if possible
-
File Permissions:
chmod 755 public chmod 750 storage chmod 640 .env
-
Remove Development Files:
rm -rf tests/
-
Enable HTTPS:
- Install SSL certificate (Let's Encrypt recommended)
- Force HTTPS redirects in web server config
-
PHP Configuration (php.ini):
display_errors = Off log_errors = On error_log = /var/log/php_errors.log expose_php = Off session.cookie_httponly = 1 session.cookie_secure = 1
-
Enable PHP OPcache:
opcache.enable=1 opcache.memory_consumption=256 opcache.max_accelerated_files=10000
-
Database Indexing: All critical indexes are included in
database.sql -
CDN: Serve static assets (CSS, JS, images) from a CDN
-
Caching: Implement Redis/Memcached for session storage (optional)
SplashContent/
├── app/
│ ├── controllers/ # Application controllers
│ ├── models/ # Database models
│ ├── views/ # View templates
│ ├── core/ # Core framework (Router, Controller, Model, Database)
│ └── helpers/ # Helper classes (AiService, EmailService, etc.)
├── config/ # Configuration files
├── public/ # Public web root
│ ├── index.php # Main entry point
│ ├── .htaccess # Apache rewrite rules
│ └── assets/ # CSS, JS, images
├── storage/
│ └── uploads/ # User uploaded files
├── tests/ # Test files
├── database.sql # Database schema + seed data
├── .env.example # Environment template
└── README.md # This file
- Models: Handle all database operations (CRUD)
- Controllers: Process requests, call models, return views
- Views: Display data (minimal PHP logic)
- Single database
- All main tables include
tenant_idcolumn - Models auto-filter by
tenant_id - Authenticated user's tenant is loaded in session
- Complete data isolation between tenants
- platform_admin: Full platform access
- tenant_admin: Manage their tenant (users, settings, billing)
- user: Generate content, view history
- Insert into
templatestable:
INSERT INTO templates (tenant_id, template_key, name, category, description, input_schema, output_type, is_global, status)
VALUES (NULL, 'new_template', 'New Template Name', 'Category', 'Description here',
'{"fields":[{"key":"field1","label":"Field 1","type":"text","required":true}]}',
'short', 1, 'active');- Add generation logic in
/app/helpers/AiService.php(if using dummy content)
Edit /app/helpers/EmailService.php:
- Configure SMTP settings
- Implement
sendEmail()method with PHPMailer or similar - Email templates are already defined (welcome, quota warning, invoices)
Solution: Enable Apache mod_rewrite:
sudo a2enmod rewrite
sudo systemctl restart apache2Solution: Check credentials in .env and ensure MySQL is running:
sudo systemctl status mysqlSolution: Check permissions:
chmod 755 storage/uploads
chown -R www-data:www-data storage/uploadsSolution: Check PHP session directory permissions:
chmod 1733 /var/lib/php/sessionsThis is a complete, production-ready codebase. Feel free to:
- Add new features
- Improve existing functionality
- Submit bug reports
- Enhance documentation
This project is open-source. Use it freely for commercial or personal projects.
For issues, questions, or feature requests, please create an issue in the repository.
Built with:
- PHP 7.0+
- MySQL/MariaDB
- Vanilla JavaScript
- Custom lightweight MVC framework
Designed for:
- Marketers
- Copywriters
- Content creators
- Digital agencies
SplashContent - AI-Powered Content Generation Made Simple.