htmlspecialchars((string)$v, ENT_QUOTES, 'UTF-8');
// ─────────────────────────────────────────────────────────────
// Config: where CP gets trial notifications
// ─────────────────────────────────────────────────────────────
const CP_EMAIL = 'askklinflow@gmail.com'; // Control Panel / team inbox
const FROM_EMAIL = 'no-reply@klinflow.com'; // domain email (SPF/DKIM)
// ─────────────────────────────────────────────────────────────
// Helper functions
// ─────────────────────────────────────────────────────────────
function pdo(): PDO {
return DB::pdo();
}
function normalise_slug(string $slug): string {
$slug = strtolower(trim($slug));
$slug = preg_replace('/[^a-z0-9-]+/', '-', $slug) ?? '';
$slug = preg_replace('/-+/', '-', $slug) ?? '';
return trim($slug, '-');
}
function reserved_slugs(): array {
return [
'www','web','app','apps','api','cp','admin','root','system',
'tenant','login','signup','pricing','public','static','assets'
];
}
function slug_taken(string $slug): ?string {
$pdo = pdo();
// Existing organizations
$stmt = $pdo->prepare('SELECT id FROM cp_organizations WHERE slug = :slug LIMIT 1');
$stmt->execute(['slug' => $slug]);
if ($stmt->fetchColumn()) {
return 'taken';
}
// Pending signups
try {
$stmt2 = $pdo->prepare('SELECT id FROM cp_trial_signups WHERE slug = :slug LIMIT 1');
$stmt2->execute(['slug' => $slug]);
if ($stmt2->fetchColumn()) {
return 'pending';
}
} catch (Throwable $e) {
// If cp_trial_signups not yet created, ignore
}
return null; // available
}
/**
* Notify KlinFlow CP that a new trial signup was created.
*/
function notify_cp(
int $signupId,
string $company,
string $slug,
string $contactName,
string $email,
array $modules,
string $notes,
string $ip,
string $ua
): void {
$to = CP_EMAIL;
$subject = "[KlinFlow • Trial Signup] {$company} ({$slug})";
$from = FROM_EMAIL;
$mods = $modules ? implode(', ', $modules) : '(none)';
$notesText = $notes !== '' ? $notes : '(no additional notes)';
$body = "New trial signup received:\n\n"
. "Signup ID: {$signupId}\n"
. "Company: {$company}\n"
. "Slug: {$slug}\n"
. "Contact: {$contactName}\n"
. "Email: {$email}\n"
. "Modules: {$mods}\n"
. "Notes: {$notesText}\n\n"
. "IP: {$ip}\n"
. "User-Agent:\n{$ua}\n\n"
. "Next steps (manual):\n"
. "1) Validate the org and contact.\n"
. "2) Create cp_organizations row with slug='{$slug}'.\n"
. "3) Create tenant user using stored password_hash from cp_trial_signups.\n"
. "4) Enable requested modules in Control Panel.\n";
$headers = "From: KlinFlow Trials <{$from}>\r\n";
$headers .= "Reply-To: {$email}\r\n";
$headers .= "Content-Type: text/plain; charset=UTF-8\r\n";
@mail($to, $subject, $body, $headers);
}
/**
* Send a “we got your trial request” email to the requester,
* using the unified App\Services\Mailer.
*/
function send_trial_welcome_email(
string $toEmail,
string $contactName,
string $company,
string $slug,
array $modules
): void {
try {
$mailer = new Mailer();
$safeName = trim($contactName) !== ''
? $contactName
: ucfirst((string)strtok((string)$toEmail, '@'));
$scheme = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
$host = $_SERVER['HTTP_HOST'] ?? 'klinflow.com';
$base = $scheme.'://'.$host;
$logoUrl = $base . '/assets/img/logo/klinflow.png';
$brandColor = '#228B22';
$modulesLabel = $modules ? implode(', ', $modules) : '(no modules selected)';
$tenantUrl = $base . '/t/' . rawurlencode($slug) . '/dashboard';
ob_start();
?>
Your KlinFlow trial request
|
|
Thank you for your KlinFlow trial request
Dear = htmlspecialchars($safeName, ENT_QUOTES, 'UTF-8') ?>,
We’ve received your request to create a KlinFlow trial tenant for
= htmlspecialchars($company, ENT_QUOTES, 'UTF-8') ?>.
Requested tenant slug:
/t/= htmlspecialchars($slug, ENT_QUOTES, 'UTF-8') ?>/apps/pos
|
Modules you requested:
= htmlspecialchars($modulesLabel, ENT_QUOTES, 'UTF-8') ?>
|
What happens next:
- Our team will review your request and validate the details.
- We’ll provision your tenant and initial admin user.
- You’ll receive another welcome email with your login link and password once everything is ready.
Once your tenant is activated, your dashboard will be available at:
= htmlspecialchars($tenantUrl, ENT_QUOTES, 'UTF-8') ?>
— Team KlinFlow
|
|
|
|
sendWelcome($toEmail, $subject, $html, $text);
} catch (\Throwable $e) {
error_log('[signup] trial welcome mail failed: '.$e->getMessage());
}
}
// ─────────────────────────────────────────────────────────────
// Handle POST
// ─────────────────────────────────────────────────────────────
$errors = [];
$success = false;
// Keep old values for sticky form
$old = [
'company' => '',
'slug' => '',
'name' => '',
'email' => '',
'notes' => '',
'modules' => [],
];
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$company = trim((string)($_POST['company'] ?? ''));
$slugRaw = (string)($_POST['slug'] ?? '');
$slug = normalise_slug($slugRaw);
$contactName = trim((string)($_POST['name'] ?? ''));
$email = trim((string)($_POST['email'] ?? ''));
$passwordPlain = (string)($_POST['password'] ?? '');
$confirm = (string)($_POST['confirm'] ?? '');
$modules = isset($_POST['modules']) && is_array($_POST['modules']) ? array_values($_POST['modules']) : [];
$notes = trim((string)($_POST['notes'] ?? ''));
$termsAccepted = isset($_POST['terms']);
$source = 'public-trial-signup';
$old = [
'company' => $company,
'slug' => $slug,
'name' => $contactName,
'email' => $email,
'notes' => $notes,
'modules' => $modules,
];
// Validation
if ($company === '') {
$errors['company'] = 'Company/organization is required.';
}
if ($slug === '') {
$errors['slug'] = 'Slug is required.';
} elseif (strlen($slug) < 3) {
$errors['slug'] = 'Slug must be at least 3 characters.';
} elseif (strlen($slug) > 40) {
$errors['slug'] = 'Slug may not exceed 40 characters.';
} elseif (in_array($slug, reserved_slugs(), true)) {
$errors['slug'] = 'This slug is reserved by KlinFlow.';
} else {
$status = slug_taken($slug);
if ($status === 'taken') {
$errors['slug'] = 'This slug is already in use by an existing tenant.';
} elseif ($status === 'pending') {
$errors['slug'] = 'A trial request already exists for this slug.';
}
}
if ($contactName === '') {
$errors['name'] = 'Your name is required.';
}
if ($email === '' || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
$errors['email'] = 'A valid email address is required.';
}
if ($passwordPlain === '' || strlen($passwordPlain) < 8) {
$errors['password'] = 'Password must be at least 8 characters.';
}
if ($confirm === '' || $confirm !== $passwordPlain) {
$errors['confirm'] = 'Passwords must match.';
}
if (count($modules) === 0) {
$errors['modules'] = 'Please select at least one module.';
}
if (!$termsAccepted) {
$errors['terms'] = 'You must accept the terms to continue.';
}
if (!$errors) {
$pdo = pdo();
$passwordHash = password_hash($passwordPlain, PASSWORD_DEFAULT);
$ip = $_SERVER['REMOTE_ADDR'] ?? '';
$ua = $_SERVER['HTTP_USER_AGENT'] ?? '';
try {
$stmt = $pdo->prepare(
'INSERT INTO cp_trial_signups
(company, slug, contact_name, email, password_hash, modules, notes,
source, created_at, ip_address, user_agent, status)
VALUES
(:company, :slug, :contact_name, :email, :password_hash, :modules, :notes,
:source, NOW(), :ip, :ua, :status)'
);
$stmt->execute([
'company' => $company,
'slug' => $slug,
'contact_name' => $contactName,
'email' => $email,
'password_hash' => $passwordHash,
'modules' => json_encode($modules, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE),
'notes' => $notes,
'source' => $source,
'ip' => $ip,
'ua' => $ua,
'status' => 'pending',
]);
$signupId = (int)$pdo->lastInsertId();
// Notify CP team inbox
notify_cp($signupId, $company, $slug, $contactName, $email, $modules, $notes, $ip, $ua);
// Send confirmation email to requester
send_trial_welcome_email($email, $contactName, $company, $slug, $modules);
$success = true;
// Reset sensitive fields
$old['password'] = '';
$old['confirm'] = '';
} catch (Throwable $e) {
error_log('[signup] save failed: '.$e->getMessage());
$errors['__global'] = 'Failed to save your request. Please try again later.';
}
}
}
?>
Start your 14-day Free Trial — KlinFlow
Skip to main
14-Day Free Trial
Join 100+ businesses running on Bangladesh's most advanced multi-tenant ERP platform. No credit card required.
-
Access to all premium modules
-
Dedicated slug (your-org.klinflow.com)
-
Priority local support
Request Sent!
Check your email for login details. We will activate your tenant shortly.
Already have an account? Sign in here