Compare commits

..

No commits in common. "ai-dev" and "master" have entirely different histories.

109 changed files with 149 additions and 9163 deletions

View File

@ -1,17 +0,0 @@
<?php
include __DIR__ . '/../db/config.php';
if (!isset($_GET['id'])) {
header('Location: customers.php');
exit;
}
$pdo = db();
// The ON DELETE CASCADE constraint on the orders table will automatically delete related orders.
$stmt = $pdo->prepare('DELETE FROM customers WHERE id = ?');
$stmt->execute([$_GET['id']]);
header('Location: customers.php');
exit;
?>

View File

@ -1,65 +0,0 @@
<?php
include __DIR__ . '/../db/config.php';
include 'header.php';
$pdo = db();
$customer = [
'id' => '',
'name' => '',
'email' => '',
'service_address' => ''
];
$page_title = 'Edit Customer';
if (!isset($_GET['id'])) {
echo "<div class='alert alert-danger'>No customer ID specified.</div>";
include 'footer.php';
exit;
}
$stmt = $pdo->prepare('SELECT * FROM customers WHERE id = ?');
$stmt->execute([$_GET['id']]);
$customer = $stmt->fetch();
if (!$customer) {
echo "<div class='alert alert-danger'>Customer not found.</div>";
include 'footer.php';
exit;
}
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$name = $_POST['name'] ?? '';
$email = $_POST['email'] ?? '';
$service_address = $_POST['service_address'] ?? '';
$customer_id = $_POST['id'] ?? null;
if ($customer_id) {
$stmt = $pdo->prepare('UPDATE customers SET name = ?, email = ?, service_address = ? WHERE id = ?');
$stmt->execute([$name, $email, $service_address, $customer_id]);
header('Location: customers.php');
exit;
}
}
?>
<h1><?php echo $page_title; ?></h1>
<form action="customer_edit.php?id=<?php echo htmlspecialchars($customer['id']); ?>" method="post">
<input type="hidden" name="id" value="<?php echo htmlspecialchars($customer['id']); ?>">
<div class="mb-3">
<label for="name" class="form-label">Name</label>
<input type="text" class="form-control" id="name" name="name" value="<?php echo htmlspecialchars($customer['name']); ?>" required>
</div>
<div class="mb-3">
<label for="email" class="form-label">Email</label>
<input type="email" class="form-control" id="email" name="email" value="<?php echo htmlspecialchars($customer['email']); ?>" required>
</div>
<div class="mb-3">
<label for="service_address" class="form-label">Service Address</label>
<input type="text" class="form-control" id="service_address" name="service_address" value="<?php echo htmlspecialchars($customer['service_address']); ?>" required>
</div>
<button type="submit" class="btn btn-primary">Save Customer</button>
<a href="customers.php" class="btn btn-secondary">Cancel</a>
</form>
<?php include 'footer.php'; ?>

View File

@ -1,48 +0,0 @@
<?php
include __DIR__ . '/../db/config.php';
include 'header.php';
$pdo = db();
$stmt = $pdo->query('SELECT * FROM customers ORDER BY created_at DESC');
$customers = $stmt->fetchAll();
?>
<div class="d-flex justify-content-between align-items-center mb-4">
<h1>Customers</h1>
</div>
<table class="table table-striped table-bordered">
<thead class="table-dark">
<tr>
<th>ID</th>
<th>Name</th>
<th>Email</th>
<th>Service Address</th>
<th>Joined On</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<?php if (empty($customers)): ?>
<tr>
<td colspan="6" class="text-center">No customers found.</td>
</tr>
<?php else: ?>
<?php foreach ($customers as $customer): ?>
<tr>
<td><?php echo htmlspecialchars($customer['id']); ?></td>
<td><?php echo htmlspecialchars($customer['name']); ?></td>
<td><?php echo htmlspecialchars($customer['email']); ?></td>
<td><?php echo htmlspecialchars($customer['service_address']); ?></td>
<td><?php echo htmlspecialchars(date('Y-m-d', strtotime($customer['created_at']))); ?></td>
<td>
<a href="customer_edit.php?id=<?php echo $customer['id']; ?>" class="btn btn-sm btn-primary">Edit</a>
<a href="customer_delete.php?id=<?php echo $customer['id']; ?>" class="btn btn-sm btn-danger" onclick="return confirm('Are you sure?');">Delete</a>
</td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
<?php include 'footer.php'; ?>

View File

@ -1,4 +0,0 @@
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>

View File

@ -1,49 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Admin Panel</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
<style>
body {
display: flex;
min-height: 100vh;
background-color: #f8f9fa;
}
.sidebar {
width: 250px;
background: #343a40;
color: white;
flex-shrink: 0;
}
.sidebar .nav-link {
color: #adb5bd;
padding: 1rem;
}
.sidebar .nav-link.active, .sidebar .nav-link:hover {
color: #fff;
background: #495057;
}
.sidebar .nav-link .fa {
margin-right: 10px;
}
.content {
flex-grow: 1;
padding: 2rem;
}
</style>
</head>
<body>
<div class="sidebar">
<h4 class="text-center p-3 mb-0">Admin</h4>
<nav class="nav flex-column">
<a class="nav-link" href="/admin/index.php"><i class="fa fa-tachometer-alt"></i>Dashboard</a>
<a class="nav-link" href="/admin/customers.php"><i class="fa fa-users"></i>Customers</a>
<a class="nav-link" href="/admin/orders.php"><i class="fa fa-box-open"></i>Orders</a>
<a class="nav-link" href="/admin/plans.php"><i class="fa fa-list-alt"></i>Plans</a>
<a class="nav-link" href="/admin/pages.php"><i class="fa fa-file-alt"></i>Pages</a>
</nav>
</div>
<div class="content">

View File

@ -1,6 +0,0 @@
<?php include 'header.php'; ?>
<h1>Dashboard</h1>
<p>Welcome to the admin dashboard. Use the sidebar to navigate through the different sections.</p>
<?php include 'footer.php'; ?>

View File

@ -1,5 +0,0 @@
<?php
session_start();
session_destroy();
header('Location: /admin/index.php');
exit;

View File

@ -1,60 +0,0 @@
<?php
include __DIR__ . '/../db/config.php';
include 'header.php';
$pdo = db();
$stmt = $pdo->query('SELECT o.id, c.name as customer_name, p.name as plan_name, o.order_status, o.amount, o.created_at FROM orders o JOIN customers c ON o.customer_id = c.id JOIN plans p ON o.plan_id = p.id ORDER BY o.created_at DESC');
$orders = $stmt->fetchAll();
function get_status_badge($status) {
switch (strtolower($status)) {
case 'completed':
case 'active':
return 'bg-success';
case 'pending':
return 'bg-warning';
case 'failed':
case 'cancelled':
return 'bg-danger';
default:
return 'bg-secondary';
}
}
?>
<div class="d-flex justify-content-between align-items-center mb-4">
<h1>Orders</h1>
</div>
<table class="table table-striped table-bordered">
<thead class="table-dark">
<tr>
<th>Order ID</th>
<th>Customer</th>
<th>Plan</th>
<th>Amount</th>
<th>Status</th>
<th>Order Date</th>
</tr>
</thead>
<tbody>
<?php if (empty($orders)): ?>
<tr>
<td colspan="6" class="text-center">No orders found.</td>
</tr>
<?php else: ?>
<?php foreach ($orders as $order): ?>
<tr>
<td><?php echo htmlspecialchars($order['id']); ?></td>
<td><?php echo htmlspecialchars($order['customer_name']); ?></td>
<td><?php echo htmlspecialchars($order['plan_name']); ?></td>
<td>$<?php echo htmlspecialchars(number_format($order['amount'], 2)); ?></td>
<td><span class="badge <?php echo get_status_badge($order['order_status']); ?>"><?php echo htmlspecialchars(ucfirst($order['order_status'])); ?></span></td>
<td><?php echo htmlspecialchars(date('Y-m-d H:i', strtotime($order['created_at']))); ?></td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
<?php include 'footer.php'; ?>

View File

@ -1,12 +0,0 @@
<?php
require_once '../db/config.php';
$id = $_GET['id'] ?? null;
if ($id) {
$stmt = db()->prepare('DELETE FROM pages WHERE id = ?');
$stmt->execute([$id]);
}
header('Location: pages.php');
exit;

View File

@ -1,55 +0,0 @@
<?php
require_once '../db/config.php';
$id = $_GET['id'] ?? null;
$page = [];
$title = 'Create Page';
if ($id) {
$stmt = db()->prepare('SELECT * FROM pages WHERE id = ?');
$stmt->execute([$id]);
$page = $stmt->fetch();
$title = 'Edit Page';
}
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$slug = $_POST['slug'];
$page_title = $_POST['title'];
$content = $_POST['content'];
if ($id) {
$stmt = db()->prepare('UPDATE pages SET slug = ?, title = ?, content = ? WHERE id = ?');
$stmt->execute([$slug, $page_title, $content, $id]);
} else {
$stmt = db()->prepare('INSERT INTO pages (slug, title, content) VALUES (?, ?, ?)');
$stmt->execute([$slug, $page_title, $content]);
}
header('Location: pages.php');
exit;
}
include 'header.php';
?>
<h1><?php echo $title; ?></h1>
<form method="POST">
<div class="mb-3">
<label for="title" class="form-label">Title</label>
<input type="text" class="form-control" id="title" name="title" value="<?php echo htmlspecialchars($page['title'] ?? ''); ?>" required>
</div>
<div class="mb-3">
<label for="slug" class="form-label">Slug</label>
<input type="text" class="form-control" id="slug" name="slug" value="<?php echo htmlspecialchars($page['slug'] ?? ''); ?>" required>
<div class="form-text">The slug is the URL-friendly version of the name. It is usually all lowercase and contains only letters, numbers, and hyphens.</div>
</div>
<div class="mb-3">
<label for="content" class="form-label">Content</label>
<textarea class="form-control" id="content" name="content" rows="10" required><?php echo htmlspecialchars($page['content'] ?? ''); ?></textarea>
</div>
<button type="submit" class="btn btn-primary">Save</button>
<a href="pages.php" class="btn btn-secondary">Cancel</a>
</form>
<?php include 'footer.php'; ?>

View File

@ -1,37 +0,0 @@
<?php
require_once '../db/config.php';
$pages = db()->query('SELECT * FROM pages ORDER BY title ASC')->fetchAll();
include 'header.php';
?>
<div class="d-flex justify-content-between align-items-center mb-4">
<h1>Pages</h1>
<a href="page_edit.php" class="btn btn-primary">Create Page</a>
</div>
<table class="table table-striped">
<thead>
<tr>
<th>Title</th>
<th>Slug</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<?php foreach ($pages as $page): ?>
<tr>
<td><?php echo htmlspecialchars($page['title']); ?></td>
<td><?php echo htmlspecialchars($page['slug']); ?></td>
<td>
<a href="page_edit.php?id=<?php echo $page['id']; ?>" class="btn btn-sm btn-outline-primary">Edit</a>
<a href="page_delete.php?id=<?php echo $page['id']; ?>" class="btn btn-sm btn-outline-danger" onclick="return confirm('Are you sure?')">Delete</a>
<a href="/page.php?slug=<?php echo htmlspecialchars($page['slug']); ?>" class="btn btn-sm btn-outline-secondary" target="_blank">View</a>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php include 'footer.php'; ?>

View File

@ -1,15 +0,0 @@
<?php
include __DIR__ . '/../db/config.php';
if (!isset($_GET['id'])) {
header('Location: plans.php');
exit;
}
$pdo = db();
$stmt = $pdo->prepare('DELETE FROM plans WHERE id = ?');
$stmt->execute([$_GET['id']]);
header('Location: plans.php');
exit;
?>

View File

@ -1,81 +0,0 @@
<?php
include __DIR__ . '/../db/config.php';
include 'header.php';
$pdo = db();
$plan = [
'id' => '',
'name' => '',
'speed_mbps' => '',
'price_monthly' => '',
'contract_months' => '',
'description' => ''
];
$page_title = 'Add New Plan';
if (isset($_GET['id'])) {
$page_title = 'Edit Plan';
$stmt = $pdo->prepare('SELECT * FROM plans WHERE id = ?');
$stmt->execute([$_GET['id']]);
$plan = $stmt->fetch();
if (!$plan) {
echo "<div class='alert alert-danger'>Plan not found.</div>";
include 'footer.php';
exit;
}
}
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$name = $_POST['name'] ?? '';
$speed_mbps = $_POST['speed_mbps'] ?? 0;
$price_monthly = $_POST['price_monthly'] ?? 0;
$contract_months = $_POST['contract_months'] ?? 0;
$description = $_POST['description'] ?? '';
$plan_id = $_POST['id'] ?? null;
if ($plan_id) {
// Update
$stmt = $pdo->prepare('UPDATE plans SET name = ?, speed_mbps = ?, price_monthly = ?, contract_months = ?, description = ? WHERE id = ?');
$stmt->execute([$name, $speed_mbps, $price_monthly, $contract_months, $description, $plan_id]);
} else {
// Insert
$stmt = $pdo->prepare('INSERT INTO plans (name, speed_mbps, price_monthly, contract_months, description) VALUES (?, ?, ?, ?, ?)');
$stmt->execute([$name, $speed_mbps, $price_monthly, $contract_months, $description]);
}
header('Location: plans.php');
exit;
}
?>
<h1><?php echo $page_title; ?></h1>
<form action="plan_edit.php<?php echo isset($plan['id']) && $plan['id'] ? '?id='.$plan['id'] : '' ?>" method="post">
<?php if (isset($plan['id']) && $plan['id']): ?>
<input type="hidden" name="id" value="<?php echo htmlspecialchars($plan['id']); ?>">
<?php endif; ?>
<div class="mb-3">
<label for="name" class="form-label">Plan Name</label>
<input type="text" class="form-control" id="name" name="name" value="<?php echo htmlspecialchars($plan['name']); ?>" required>
</div>
<div class="mb-3">
<label for="speed_mbps" class="form-label">Speed (Mbps)</label>
<input type="number" class="form-control" id="speed_mbps" name="speed_mbps" value="<?php echo htmlspecialchars($plan['speed_mbps']); ?>" required>
</div>
<div class="mb-3">
<label for="price_monthly" class="form-label">Price (Monthly)</label>
<input type="number" step="0.01" class="form-control" id="price_monthly" name="price_monthly" value="<?php echo htmlspecialchars($plan['price_monthly']); ?>" required>
</div>
<div class="mb-3">
<label for="contract_months" class="form-label">Contract (Months)</label>
<input type="number" class="form-control" id="contract_months" name="contract_months" value="<?php echo htmlspecialchars($plan['contract_months']); ?>" required>
</div>
<div class="mb-3">
<label for="description" class="form-label">Description</label>
<textarea class="form-control" id="description" name="description" rows="3"><?php echo htmlspecialchars($plan['description']); ?></textarea>
</div>
<button type="submit" class="btn btn-primary">Save Plan</button>
<a href="plans.php" class="btn btn-secondary">Cancel</a>
</form>
<?php include 'footer.php'; ?>

View File

@ -1,49 +0,0 @@
<?php
include __DIR__ . '/../db/config.php';
include 'header.php';
$pdo = db();
$stmt = $pdo->query('SELECT * FROM plans ORDER BY price_monthly');
$plans = $stmt->fetchAll();
?>
<div class="d-flex justify-content-between align-items-center mb-4">
<h1>Internet Plans</h1>
<a href="plan_edit.php" class="btn btn-success">Add New Plan</a>
</div>
<table class="table table-striped table-bordered">
<thead class="table-dark">
<tr>
<th>ID</th>
<th>Name</th>
<th>Speed</th>
<th>Price (Monthly)</th>
<th>Contract Length</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<?php if (empty($plans)): ?>
<tr>
<td colspan="6" class="text-center">No plans found.</td>
</tr>
<?php else: ?>
<?php foreach ($plans as $plan): ?>
<tr>
<td><?php echo htmlspecialchars($plan['id']); ?></td>
<td><?php echo htmlspecialchars($plan['name']); ?></td>
<td><?php echo htmlspecialchars($plan['speed_mbps']); ?> Mbps</td>
<td>$<?php echo htmlspecialchars(number_format($plan['price_monthly'], 2)); ?></td>
<td><?php echo htmlspecialchars($plan['contract_months']); ?> months</td>
<td>
<a href="plan_edit.php?id=<?php echo $plan['id']; ?>" class="btn btn-sm btn-primary">Edit</a>
<a href="plan_delete.php?id=<?php echo $plan['id']; ?>" class="btn btn-sm btn-danger" onclick="return confirm('Are you sure?');">Delete</a>
</td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
<?php include 'footer.php'; ?>

View File

@ -1,75 +0,0 @@
<?php
header('Content-Type: application/json');
require_once __DIR__ . '/../db/config.php';
// 1. Fetch plans from the database to create a knowledge base.
$knowledge_base = "";
try {
$pdo = db();
$stmt = $pdo->query("SELECT name, speed_mbps, price_monthly, contract_length_months FROM plans ORDER BY price_monthly ASC");
$plans = $stmt->fetchAll(PDO::FETCH_ASSOC);
if ($plans) {
$knowledge_base .= "Here is a list of our current internet plans:\n\n";
foreach ($plans as $plan) {
$knowledge_base .= "- Plan Name: " . $plan['name'] . "\n";
$knowledge_base .= " - Speed: " . $plan['speed_mbps'] . " Mbps\n";
$knowledge_base .= " - Price: $" . $plan['price_monthly'] . " per month\n";
$knowledge_base .= " - Contract: " . $plan['contract_length_months'] . " months\n\n";
}
$knowledge_base .= "You are a helpful and friendly customer support assistant for a telecommunications company. Your goal is to answer customer questions based ONLY on the information provided in this knowledge base. Do not invent or assume any details. If the answer is not in the knowledge base, say 'I'm sorry, I don't have that information, but I can connect you with a human agent.' Keep your answers concise and to the point.";
}
} catch (PDOException $e) {
// In a real app, you'd log this error.
// For now, we'll proceed with an empty knowledge base on failure.
}
// 2. Get the user's question
$data = json_decode(file_get_contents('php://input'), true);
$user_question = $data['question'] ?? '';
if (empty($user_question)) {
echo json_encode(['error' => 'No question provided.']);
exit;
}
// 3. Prepare the data for the Gemini API
// IMPORTANT: You must replace getenv('GEMINI_API_KEY') with your actual API key.
$api_key = getenv('GEMINI_API_KEY');
$api_url = 'https://generativelanguage.googleapis.com/v1beta/models/gemini-pro:generateContent?key=' . $api_key;
$payload = [
'contents' => [
[
'parts' => [
['text' => $knowledge_base . "\n\nCustomer Question: " . $user_question]
]
]
]
];
// 4. Use cURL to make the API call
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $api_url);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // For local development only
$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
// 5. Process and return the response
if ($http_code === 200) {
$result = json_decode($response, true);
$ai_response = $result['candidates'][0]['content']['parts'][0]['text'] ?? 'I am unable to answer at this time.';
echo json_encode(['reply' => $ai_response]);
} else {
// Log the error response for debugging
error_log("Gemini API Error: HTTP " . $http_code . " - " . $response);
echo json_encode(['error' => 'Failed to get a response from the AI assistant. Please try again later.']);
}

View File

@ -1,54 +0,0 @@
<?php
header('Content-Type: application/json');
require_once __DIR__ . '/../db/config.php';
$response = [
'success' => false,
'message' => 'An error occurred.',
'serviceable' => false
];
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
$response['message'] = 'Invalid request method.';
echo json_encode($response);
exit;
}
$input = json_decode(file_get_contents('php://input'), true);
$address = $input['address'] ?? '';
if (empty($address)) {
$response['message'] = 'Address cannot be empty.';
echo json_encode($response);
exit;
}
// This is a very simple search. A real-world application would need a more robust
// address parsing and matching engine (e.g., using Google Geocoding API and spatial data).
// For this demo, we'll just do a broad search on the input string.
try {
$pdo = db();
$stmt = $pdo->prepare(
"SELECT COUNT(*) FROM serviceable_addresses WHERE CONCAT_WS(' ', street, suburb, state, postcode) LIKE ?"
);
$stmt->execute(['%' . $address . '%']);
$count = $stmt->fetchColumn();
if ($count > 0) {
$response['serviceable'] = true;
$response['message'] = 'Great news! Your address is serviceable.';
} else {
$response['serviceable'] = false;
$response['message'] = "Sorry, we don't seem to be in your area yet. Please contact us for more information.";
}
$response['success'] = true;
} catch (PDOException $e) {
// In a real app, you would log this error, not expose it to the user.
$response['message'] = 'Database error.'; // Generic message for the user
// error_log($e->getMessage()); // Example of logging
}
echo json_encode($response);

View File

@ -1,55 +0,0 @@
<?php
require_once __DIR__ . '/../vendor/autoload.php';
require_once __DIR__ . '/../db/config.php';
// This is your test secret API key. Don't hardcode this in a real app.
\Stripe\Stripe::setApiKey('sk_test_51Hh9Y2L9s5P2Q8Z4sYgY8Z4sYgY8Z4sYgY8Z4sYgY8Z4sYgY8Z4sYgY8Z4sYgY8Z4sYgY8Z4sYgY8Z4');
header('Content-Type: application/json');
function calculateOrderAmount(object $plan): int {
// Calculate 10% GST
$gst = $plan->price_monthly * 0.10;
$total = $plan->price_monthly + $gst;
// Return amount in cents
return round($total * 100);
}
try {
$json_str = file_get_contents('php://input');
$json_obj = json_decode($json_str);
if (!isset($json_obj->plan_id)) {
throw new Exception("Plan ID not provided.");
}
$pdo = db();
$stmt = $pdo->prepare("SELECT * FROM plans WHERE id = ? AND is_active = 1");
$stmt->execute([$json_obj->plan_id]);
$plan = $stmt->fetch(PDO::FETCH_OBJ);
if (!$plan) {
throw new Exception("Plan not found.");
}
$paymentIntent = \Stripe\PaymentIntent::create([
'amount' => calculateOrderAmount($plan),
'currency' => 'aud',
'automatic_payment_methods' => [
'enabled' => true,
],
'metadata' => [
'plan_id' => $plan->id
]
]);
echo json_encode([
'clientSecret' => $paymentIntent->client_secret,
]);
} catch (Error $e) {
http_response_code(500);
echo json_encode(['error' => $e->getMessage()]);
} catch (Exception $e) {
http_response_code(400);
echo json_encode(['error' => $e->getMessage()]);
}

View File

@ -1,76 +0,0 @@
<?php
require_once __DIR__ . '/../vendor/autoload.php';
require_once __DIR__ . '/../db/config.php';
\Stripe\Stripe::setApiKey('sk_test_51Hh9Y2L9s5P2Q8Z4sYgY8Z4sYgY8Z4sYgY8Z4sYgY8Z4sYgY8Z4sYgY8Z4sYgY8Z4sYgY8Z4sYgY8Z4');
header('Content-Type: application/json');
$json_str = file_get_contents('php://input');
$json_obj = json_decode($json_str);
$pdo = db();
try {
// 1. Validation
if (empty($json_obj->plan_id) || empty($json_obj->name) || empty($json_obj->email) || empty($json_obj->address) || empty($json_obj->password)) {
throw new Exception('Incomplete data provided.');
}
// 2. Fetch Plan
$stmt = $pdo->prepare("SELECT * FROM plans WHERE id = ?");
$stmt->execute([$json_obj->plan_id]);
$plan = $stmt->fetch(PDO::FETCH_OBJ);
if (!$plan) {
throw new Exception('Plan not found.');
}
$order_amount = $plan->price_monthly; // Amount in dollars
// 3. Create Stripe Customer
$stripe_customer = \Stripe\Customer::create([
'name' => $json_obj->name,
'email' => $json_obj->email,
'address' => [
'line1' => $json_obj->address
],
]);
// 4. Create Local Customer
$hashed_password = password_hash($json_obj->password, PASSWORD_DEFAULT);
$stmt = $pdo->prepare("INSERT INTO customers (name, email, password, service_address, stripe_customer_id) VALUES (?, ?, ?, ?, ?)");
$stmt->execute([$json_obj->name, $json_obj->email, $hashed_password, $json_obj->address, $stripe_customer->id]);
$customer_id = $pdo->lastInsertId();
// 5. Create Local Order
$stmt = $pdo->prepare("INSERT INTO orders (customer_id, plan_id, order_status, amount) VALUES (?, ?, 'pending', ?)");
$stmt->execute([$customer_id, $plan->id, $order_amount]);
$order_id = $pdo->lastInsertId();
// 6. Create Stripe Payment Intent
$paymentIntent = \Stripe\PaymentIntent::create([
'customer' => $stripe_customer->id,
'amount' => round($order_amount * 100), // Amount in cents
'currency' => 'aud',
'automatic_payment_methods' => [
'enabled' => true,
],
'metadata' => [
'order_id' => $order_id,
'customer_id' => $customer_id,
'plan_id' => $plan->id
]
]);
// 7. Update Local Order with Payment Intent ID
$stmt = $pdo->prepare("UPDATE orders SET stripe_payment_intent_id = ? WHERE id = ?");
$stmt->execute([$paymentIntent->id, $order_id]);
// 8. Return Client Secret
echo json_encode([
'clientSecret' => $paymentIntent->client_secret,
]);
} catch (Exception $e) {
http_response_code(500);
echo json_encode(['error' => $e->getMessage()]);
}

View File

@ -1,32 +0,0 @@
<?php
require_once __DIR__ . '/../vendor/autoload.php';
\Stripe\Stripe::setApiKey('sk_test_51Hh9Y2L9s5P2Q8Z4sYgY8Z4sYgY8Z4sYgY8Z4sYgY8Z4sYgY8Z4sYgY8Z4sYgY8Z4sYgY8Z4sYgY8Z4');
header('Content-Type: application/json');
try {
$json_str = file_get_contents('php://input');
$json_obj = json_decode($json_str);
if (empty($json_obj->payment_intent_id) || empty($json_obj->name) || empty($json_obj->email) || empty($json_obj->address)) {
throw new Exception("Missing required parameters.");
}
$paymentIntent = \Stripe\PaymentIntent::update(
$json_obj->payment_intent_id,
[
'receipt_email' => $json_obj->email,
'metadata' => [
'customer_name' => $json_obj->name,
'customer_address' => $json_obj->address
]
]
);
echo json_encode(['status' => 'success']);
} catch (Exception $e) {
http_response_code(400);
echo json_encode(['error' => $e->getMessage()]);
}

View File

@ -1,111 +0,0 @@
/* General Styles */
body {
font-family: 'Poppins', sans-serif;
padding-top: 56px; /* Adjust for fixed navbar */
}
/* Header */
.navbar-brand {
font-weight: 700;
color: #007BFF !important;
}
/* Hero Section */
.hero {
background: linear-gradient(45deg, #007BFF, #00C6FF);
color: white;
padding: 120px 0;
}
.hero h1 {
font-size: 3.5rem;
font-weight: 700;
}
.hero .lead {
font-size: 1.25rem;
margin-bottom: 2rem;
}
.hero .input-group {
box-shadow: 0 10px 30px rgba(0,0,0,0.15);
}
.hero .form-control {
border-top-left-radius: 0.5rem;
border-bottom-left-radius: 0.5rem;
}
.hero .btn {
border-top-right-radius: 0.5rem;
border-bottom-right-radius: 0.5rem;
}
/* Plans Section */
#plans {
background-color: #F8F9FA;
}
.plan-card {
background: #FFFFFF;
border: 1px solid #e9ecef;
border-radius: 0.5rem;
padding: 2.5rem;
margin-bottom: 2rem;
transition: transform 0.3s, box-shadow 0.3s;
box-shadow: 0 4px 6px rgba(0,0,0,0.05);
}
.plan-card:hover {
transform: translateY(-10px);
box-shadow: 0 15px 25px rgba(0,0,0,0.1);
}
.plan-card h3 {
font-weight: 700;
color: #007BFF;
}
.plan-card .price {
font-size: 2.5rem;
font-weight: 700;
}
.plan-card .period {
font-size: 1rem;
color: #6C757D;
}
/* Buttons */
.btn-primary {
background-color: #007BFF;
border-color: #007BFF;
padding: 0.75rem 1.5rem;
border-radius: 0.5rem;
font-weight: 700;
transition: background-color 0.2s;
}
.btn-primary:hover {
background-color: #0056b3;
border-color: #0056b3;
}
.btn-outline-primary {
border-color: #007BFF;
color: #007BFF;
padding: 0.75rem 1.5rem;
border-radius: 0.5rem;
font-weight: 700;
}
.btn-outline-primary:hover {
background-color: #007BFF;
color: white;
}
/* Footer */
footer a {
text-decoration: none;
}

View File

@ -1,80 +0,0 @@
// Smooth scrolling for anchor links
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
anchor.addEventListener('click', function (e) {
e.preventDefault();
document.querySelector(this.getAttribute('href')).scrollIntoView({
behavior: 'smooth'
});
});
});
// Address Availability Check
document.addEventListener('DOMContentLoaded', () => {
const availabilityForm = document.getElementById('availability-form');
const availabilityResult = document.getElementById('availability-result');
if (availabilityForm) {
availabilityForm.addEventListener('submit', function(e) {
e.preventDefault();
const addressInput = document.getElementById('address-input');
const address = addressInput.value;
const button = this.querySelector('button');
if (!address) {
availabilityResult.textContent = 'Please enter an address.';
availabilityResult.className = 'alert alert-warning';
availabilityResult.style.display = 'block';
return;
}
// Show loading state
button.disabled = true;
button.textContent = 'Checking...';
availabilityResult.style.display = 'none';
fetch('api/check_availability.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ address: address })
})
.then(response => response.json())
.then(data => {
if (data.success) {
if (data.serviceable) {
// Address is serviceable, scroll to plans section
document.getElementById('plans').scrollIntoView({
behavior: 'smooth'
});
// Optionally, hide the success message after a delay
setTimeout(() => {
availabilityResult.style.display = 'none';
}, 3000);
availabilityResult.textContent = data.message;
availabilityResult.className = 'alert alert-success';
} else {
// Address is not serviceable
availabilityResult.textContent = data.message;
availabilityResult.className = 'alert alert-info';
}
} else {
availabilityResult.textContent = data.message || 'An unexpected error occurred.';
availabilityResult.className = 'alert alert-danger';
}
})
.catch(error => {
console.error('Error:', error);
availabilityResult.textContent = 'A network error occurred. Please try again.';
availabilityResult.className = 'alert alert-danger';
})
.finally(() => {
availabilityResult.style.display = 'block';
button.disabled = false;
button.textContent = 'Check Availability';
});
});
}
});

View File

@ -1,102 +0,0 @@
const stripe = Stripe('pk_test_51Hh9Y2L9s5P2Q8Z4sYgY8Z4sYgY8Z4sYgY8Z4sYgY8Z4sYgY8Z4sYgY8Z4sYgY8Z4sYgY8Z4sYgY8Z4sYgY8Z4');
const form = document.querySelector("#signup-form");
form.addEventListener("submit", handleSubmit);
// Initially, disable the submit button until the form is filled
document.querySelector("#submit").disabled = true;
// Create and mount the Payment Element
const elements = stripe.elements();
const paymentElement = elements.create("payment");
paymentElement.mount("#payment-element");
// Re-enable the submit button when the Payment Element is ready
paymentElement.on('ready', () => {
document.querySelector("#submit").disabled = false;
});
async function handleSubmit(e) {
e.preventDefault();
setLoading(true);
const name = document.getElementById('name').value;
const email = document.getElementById('email').value;
const password = document.getElementById('password').value;
const passwordConfirm = document.getElementById('password_confirm').value;
const address = document.getElementById('address').value;
const planId = form.dataset.planId;
if (password !== passwordConfirm) {
showMessage("Passwords do not match.");
setLoading(false);
return;
}
if (!name || !email || !address || !planId || !password) {
showMessage("Please fill out all fields.");
setLoading(false);
return;
}
// Create customer, order, and payment intent on the server.
const response = await fetch("/api/process_signup.php", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
plan_id: planId,
name: name,
email: email,
password: password,
address: address
}),
});
const { clientSecret, error } = await response.json();
if (error) {
showMessage(error);
setLoading(false);
return;
}
// Confirm the payment with the client secret.
const { error: stripeError } = await stripe.confirmPayment({
elements,
clientSecret,
confirmParams: {
return_url: window.location.origin + "/order_confirmation.php",
receipt_email: email,
},
});
if (stripeError) {
showMessage(stripeError.message);
}
setLoading(false);
}
// ------- UI helpers -------
function showMessage(messageText) {
const messageContainer = document.querySelector("#payment-message");
messageContainer.style.display = "block";
messageContainer.textContent = messageText;
setTimeout(function () {
messageContainer.style.display = "none";
messageContainer.textContent = "";
}, 5000);
}
function setLoading(isLoading) {
if (isLoading) {
document.querySelector("#submit").disabled = true;
document.querySelector("#spinner").style.display = "inline";
document.querySelector("#button-text").style.display = "none";
} else {
document.querySelector("#submit").disabled = false;
document.querySelector("#spinner").style.display = "none";
document.querySelector("#button-text").style.display = "inline";
}
}

View File

@ -1,6 +0,0 @@
{
"name": "flatlogic/customer-project",
"require": {
"stripe/stripe-php": "^1.8"
}
}

69
composer.lock generated
View File

@ -1,69 +0,0 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "9b60f1d4a7d471b52635c3ca8c3ea56e",
"packages": [
{
"name": "stripe/stripe-php",
"version": "v1.8.0",
"source": {
"type": "git",
"url": "https://github.com/stripe/stripe-php.git",
"reference": "5eba614baf4adefffdd59d196679a16d7baf70da"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/stripe/stripe-php/zipball/5eba614baf4adefffdd59d196679a16d7baf70da",
"reference": "5eba614baf4adefffdd59d196679a16d7baf70da",
"shasum": ""
},
"require": {
"ext-curl": "*",
"php": ">=5.2"
},
"require-dev": {
"vierbergenlars/simpletest": "*"
},
"type": "library",
"autoload": {
"classmap": [
"lib/Stripe/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Stripe and contributors",
"homepage": "https://github.com/stripe/stripe-php/contributors"
}
],
"description": "Stripe PHP Library",
"homepage": "https://stripe.com/",
"keywords": [
"api",
"payment processing",
"stripe"
],
"support": {
"issues": "https://github.com/stripe/stripe-php/issues",
"source": "https://github.com/stripe/stripe-php/tree/transfers-recipients"
},
"time": "2013-04-12T18:56:41+00:00"
}
],
"packages-dev": [],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": {},
"prefer-stable": false,
"prefer-lowest": false,
"platform": {},
"platform-dev": {},
"plugin-api-version": "2.6.0"
}

Binary file not shown.

View File

@ -1,41 +0,0 @@
<?php
// Simple migration runner
require_once __DIR__ . '/config.php';
// 1. Connect without a database selected to create it
try {
$pdo_admin = new PDO('mysql:host='.DB_HOST, DB_USER, DB_PASS, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
]);
$pdo_admin->exec("CREATE DATABASE IF NOT EXISTS `".DB_NAME."`");
echo "Database `".DB_NAME."` created or already exists.\n";
} catch (PDOException $e) {
echo "Error creating database: " . $e->getMessage() . "\n";
// If we can't create the DB, we probably can't do anything else.
exit(1);
}
// 2. Now connect to the database and run migrations
$pdo = db();
$migrations_dir = __DIR__ . '/migrations';
$files = glob($migrations_dir . '/*.sql');
sort($files);
foreach ($files as $file) {
echo "Running migration: " . basename($file) . "\n";
try {
$sql = file_get_contents($file);
$pdo->exec($sql);
echo "Success.\n";
} catch (PDOException $e) {
echo "Error: " . $e->getMessage() . "\n";
// Continue on error
}
}
echo "All migrations completed.\n";
?>

View File

@ -1,17 +0,0 @@
-- Create the table for serviceable addresses
CREATE TABLE IF NOT EXISTS `serviceable_addresses` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`street` VARCHAR(255) NOT NULL,
`suburb` VARCHAR(255) NOT NULL,
`postcode` VARCHAR(10) NOT NULL,
`state` VARCHAR(10) NOT NULL,
INDEX `idx_address` (`street`, `suburb`, `postcode`, `state`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- Insert some sample data for testing
INSERT INTO `serviceable_addresses` (`street`, `suburb`, `postcode`, `state`) VALUES
('123 Fake St', 'Sydney', '2000', 'NSW'),
('456 Example Ave', 'Melbourne', '3000', 'VIC'),
('789 Sample Rd', 'Brisbane', '4000', 'QLD'),
('101 Test St', 'Perth', '6000', 'WA'),
('222 Demo Dr', 'Adelaide', '5000', 'SA');

View File

@ -1,10 +0,0 @@
-- Create the plans table
CREATE TABLE IF NOT EXISTS `plans` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`name` VARCHAR(255) NOT NULL UNIQUE,
`speed_mbps` INT NOT NULL,
`price_monthly` DECIMAL(10, 2) NOT NULL,
`contract_months` INT NOT NULL,
`description` TEXT,
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

View File

@ -1,14 +0,0 @@
-- Create the customers table
CREATE TABLE IF NOT EXISTS `customers` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`first_name` VARCHAR(100) NOT NULL,
`last_name` VARCHAR(100) NOT NULL,
`email` VARCHAR(255) NOT NULL UNIQUE,
`phone` VARCHAR(50) NULL,
`password_hash` VARCHAR(255) NOT NULL, -- For storing hashed passwords
`street_address` VARCHAR(255) NULL,
`suburb` VARCHAR(100) NULL,
`state` VARCHAR(50) NULL,
`postcode` VARCHAR(20) NULL,
`created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

View File

@ -1,13 +0,0 @@
-- Create the orders table
CREATE TABLE IF NOT EXISTS `orders` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`customer_id` INT NOT NULL,
`plan_id` INT NOT NULL,
`order_status` VARCHAR(50) NOT NULL DEFAULT 'pending', -- e.g., pending, active, cancelled
`total_amount` DECIMAL(10, 2) NOT NULL,
`order_date` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
`activation_date` DATE NULL,
`notes` TEXT NULL,
FOREIGN KEY (`customer_id`) REFERENCES `customers`(`id`) ON DELETE CASCADE,
FOREIGN KEY (`plan_id`) REFERENCES `plans`(`id`) ON DELETE RESTRICT
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

View File

@ -1,7 +0,0 @@
CREATE TABLE IF NOT EXISTS pages (
id INT AUTO_INCREMENT PRIMARY KEY,
slug VARCHAR(255) NOT NULL UNIQUE,
title VARCHAR(255) NOT NULL,
content TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

View File

@ -1 +0,0 @@
ALTER TABLE `customers` ADD `password` VARCHAR(255) NOT NULL AFTER `email`;

View File

@ -1,12 +0,0 @@
-- Seed the pages table with an "About Us" and "Terms of Service" page
INSERT INTO `pages` (`title`, `slug`, `content`) VALUES
('About Us', 'about-us', '<h1>About Us</h1><p>We are a leading provider of telecommunication services, committed to connecting you to the world. This page was generated by the CMS.</p>'),
('Terms of Service', 'terms-of-service', '<h1>Terms of Service</h1><p>By using our services, you agree to our terms. This is a sample page.</p>'),
('Privacy Policy', 'privacy-policy', '<h1>Privacy Policy</h1><p>Your privacy is important to us. This is a sample page.</p>');
-- Let's add some sample plans to make the landing page look populated.
INSERT INTO `plans` (`name`, `speed_mbps`, `price_monthly`, `contract_months`, `description`) VALUES
('Basic Connect', 25, 49.99, 12, 'Ideal for browsing and email.'),
('Family Streamer', 50, 69.99, 12, 'Perfect for streaming HD video on multiple devices.'),
('Super Fast Gamer', 100, 89.99, 24, 'Low latency for the ultimate gaming experience.'),
('Power User', 250, 109.99, 24, 'For heavy-duty usage, 4K streaming, and large downloads.');

View File

@ -1,47 +0,0 @@
</main>
<footer class="py-4 bg-dark text-white">
<div class="container">
<div class="row">
<div class="col-md-4">
<h5>Quick Links</h5>
<ul class="list-unstyled">
<li><a href="index.php#hero" class="text-white">Home</a></li>
<li><a href="index.php#plans" class="text-white">Plans</a></li>
<li><a href="support.php" class="text-white">Support</a></li>
<li><a href="index.php#about" class="text-white">About</a></li>
<li><a href="index.php#contact" class="text-white">Contact</a></li>
</ul>
</div>
<div class="col-md-4">
<h5>Our Pages</h5>
<ul class="list-unstyled">
<?php
require_once __DIR__ . '/db/config.php';
try {
$pdo = db();
$stmt = $pdo->query("SELECT * FROM pages WHERE is_published = 1 ORDER BY title");
$pages = $stmt->fetchAll();
} catch (PDOException $e) {
error_log($e->getMessage());
$pages = [];
}
foreach ($pages as $page) {
echo '<li><a href="page.php?slug=' . htmlspecialchars($page['slug']) . '" class="text-white">' . htmlspecialchars($page['title']) . '</a></li>';
}
?>
</ul>
</div>
<div class="col-md-4">
<h5>Connect</h5>
<p>&copy; <?php echo date('Y'); ?> Australia Broadband Internet. All Rights Reserved.</p>
<p><a href="privacy.php" class="text-white">Privacy Policy</a></p>
</div>
</div>
</div>
</footer>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script src="assets/js/main.js?v=<?php echo time(); ?>"></script>
</body>
</html>

View File

@ -1,45 +0,0 @@
<?php session_start(); ?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Australia Broadband Internet</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
</head>
<body>
<header class="navbar navbar-expand-lg navbar-light bg-light fixed-top">
<div class="container">
<a class="navbar-brand" href="index.php">ABI</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav ms-auto">
<li class="nav-item"><a class="nav-link" href="index.php#hero">Home</a></li>
<li class="nav-item"><a class="nav-link" href="index.php#plans">Plans</a></li>
<li class="nav-item"><a class="nav-link" href="support.php">Support</a></li>
<li class="nav-item"><a class="nav-link" href="index.php#about">About</a></li>
<li class="nav-item"><a class="nav-link" href="index.php#contact">Contact</a></li>
<?php if (isset($_SESSION['user_id'])): // Admin user ?>
<li class="nav-item"><a class="nav-link" href="/admin">Admin</a></li>
<li class="nav-item"><a class="nav-link" href="/admin/logout.php">Logout</a></li>
<?php elseif (isset($_SESSION['customer_id'])): // Customer ?>
<li class="nav-item"><a class="nav-link" href="portal.php">My Portal</a></li>
<li class="nav-item"><a class="nav-link" href="logout.php">Logout</a></li>
<?php else: // Guest ?>
<li class="nav-item"><a class="nav-link" href="login.php">Login</a></li>
<?php endif; ?>
<li class="nav-item"><a class="btn btn-primary ms-lg-3" href="index.php#hero">Check Availability</a></li>
</ul>
</div>
</div>
</header>
<main class="py-5 mt-5">

233
index.php
View File

@ -1,85 +1,150 @@
<?php include 'header.php'; ?>
<section id="hero" class="hero text-center">
<div class="container">
<h1>Fast, Reliable Internet for Your Home</h1>
<p class="lead">Check if Australia Broadband Internet is available at your address.</p>
<div class="row justify-content-center">
<div class="col-md-8">
<form id="availability-form">
<div class="input-group input-group-lg">
<input type="text" id="address-input" class="form-control" placeholder="Enter your street address, suburb and postcode...">
<button class="btn btn-primary" type="submit">Check Now</button>
</div>
</form>
<div id="availability-result" class="mt-3" style="display: none;"></div>
</div>
</div>
</div>
</section>
<?php
declare(strict_types=1);
@ini_set('display_errors', '1');
@error_reporting(E_ALL);
@date_default_timezone_set('UTC');
<section id="plans" class="py-5 bg-light">
<div class="container">
<h2 class="text-center mb-5">Our Plans</h2>
<div class="row">
<?php
require_once __DIR__ . '/db/config.php';
try {
$pdo = db();
$stmt = $pdo->query("SELECT * FROM plans ORDER BY price_monthly");
$plans = $stmt->fetchAll();
} catch (PDOException $e) {
error_log($e->getMessage());
$plans = [];
}
if (empty($plans)):
?>
<div class="col-12 text-center">
<p>No plans available at the moment. Please check back later.</p>
</div>
<?php else: ?>
<?php foreach ($plans as $plan): ?>
<div class="col-md-4 mb-4">
<div class="card h-100 shadow-sm">
<div class="card-body d-flex flex-column">
<h5 class="card-title text-center"><?php echo htmlspecialchars($plan['name']); ?></h5>
<div class="text-center my-4">
<span class="display-4 fw-bold">$<?php echo htmlspecialchars(number_format($plan['price_monthly'], 2)); ?></span>
<span class="text-muted">/mo</span>
</div>
<ul class="list-unstyled mb-4 text-center">
<li class="mb-2"><i class="bi bi-speedometer2 me-2"></i>Up to <?php echo htmlspecialchars($plan['speed_mbps']); ?> Mbps</li>
<li class="mb-2"><i class="bi bi-card-text me-2"></i><?php echo htmlspecialchars($plan['description']); ?></li>
<li class="mb-2"><i class="bi bi-calendar-check me-2"></i><?php echo htmlspecialchars($plan['contract_months']); ?> months contract</li>
</ul>
<div class="mt-auto">
<a href="signup.php?plan_id=<?php echo $plan['id']; ?>" class="btn btn-primary w-100">Sign Up Now</a>
</div>
</div>
</div>
</div>
<?php endforeach; ?>
<?php endif; ?>
</div>
</div>
</section>
<section id="about" class="bg-light py-5">
<div class="container">
<div class="row">
<div class="col-md-8 mx-auto text-center">
<h2>About Us</h2>
<p class="lead">Australia Broadband Internet is a leading provider of high-speed internet services. We are dedicated to delivering reliable and affordable connectivity to homes across Australia.</p>
</div>
</div>
</div>
</section>
<section id="contact" class="py-5">
<div class="container text-center">
<h2>Contact Us</h2>
<p>Email: support@abinet.com.au</p>
<p>Phone: 1300 864 341</p>
</div>
</section>
<?php include 'footer.php'; ?>
$phpVersion = PHP_VERSION;
$now = date('Y-m-d H:i:s');
?>
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>New Style</title>
<?php
// Read project preview data from environment
$projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? '';
$projectImageUrl = $_SERVER['PROJECT_IMAGE_URL'] ?? '';
?>
<?php if ($projectDescription): ?>
<!-- Meta description -->
<meta name="description" content='<?= htmlspecialchars($projectDescription) ?>' />
<!-- Open Graph meta tags -->
<meta property="og:description" content="<?= htmlspecialchars($projectDescription) ?>" />
<!-- Twitter meta tags -->
<meta property="twitter:description" content="<?= htmlspecialchars($projectDescription) ?>" />
<?php endif; ?>
<?php if ($projectImageUrl): ?>
<!-- Open Graph image -->
<meta property="og:image" content="<?= htmlspecialchars($projectImageUrl) ?>" />
<!-- Twitter image -->
<meta property="twitter:image" content="<?= htmlspecialchars($projectImageUrl) ?>" />
<?php endif; ?>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap" rel="stylesheet">
<style>
:root {
--bg-color-start: #6a11cb;
--bg-color-end: #2575fc;
--text-color: #ffffff;
--card-bg-color: rgba(255, 255, 255, 0.01);
--card-border-color: rgba(255, 255, 255, 0.1);
}
body {
margin: 0;
font-family: 'Inter', sans-serif;
background: linear-gradient(45deg, var(--bg-color-start), var(--bg-color-end));
color: var(--text-color);
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
text-align: center;
overflow: hidden;
position: relative;
}
body::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100"><path d="M-10 10L110 10M10 -10L10 110" stroke-width="1" stroke="rgba(255,255,255,0.05)"/></svg>');
animation: bg-pan 20s linear infinite;
z-index: -1;
}
@keyframes bg-pan {
0% { background-position: 0% 0%; }
100% { background-position: 100% 100%; }
}
main {
padding: 2rem;
}
.card {
background: var(--card-bg-color);
border: 1px solid var(--card-border-color);
border-radius: 16px;
padding: 2rem;
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.1);
}
.loader {
margin: 1.25rem auto 1.25rem;
width: 48px;
height: 48px;
border: 3px solid rgba(255, 255, 255, 0.25);
border-top-color: #fff;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.hint {
opacity: 0.9;
}
.sr-only {
position: absolute;
width: 1px; height: 1px;
padding: 0; margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap; border: 0;
}
h1 {
font-size: 3rem;
font-weight: 700;
margin: 0 0 1rem;
letter-spacing: -1px;
}
p {
margin: 0.5rem 0;
font-size: 1.1rem;
}
code {
background: rgba(0,0,0,0.2);
padding: 2px 6px;
border-radius: 4px;
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
footer {
position: absolute;
bottom: 1rem;
font-size: 0.8rem;
opacity: 0.7;
}
</style>
</head>
<body>
<main>
<div class="card">
<h1>Analyzing your requirements and generating your website…</h1>
<div class="loader" role="status" aria-live="polite" aria-label="Applying initial changes">
<span class="sr-only">Loading…</span>
</div>
<p class="hint"><?= ($_SERVER['HTTP_HOST'] ?? '') === 'appwizzy.com' ? 'AppWizzy' : 'Flatlogic' ?> AI is collecting your requirements and applying the first changes.</p>
<p class="hint">This page will update automatically as the plan is implemented.</p>
<p>Runtime: PHP <code><?= htmlspecialchars($phpVersion) ?></code> — UTC <code><?= htmlspecialchars($now) ?></code></p>
</div>
</main>
<footer>
Page updated: <?= htmlspecialchars($now) ?> (UTC)
</footer>
</body>
</html>

View File

@ -1,54 +0,0 @@
<?php
require_once __DIR__ . '/db/config.php';
include 'header.php';
$error_message = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (empty($_POST['email']) || empty($_POST['password'])) {
$error_message = 'Please enter both email and password.';
} else {
$pdo = db();
$stmt = $pdo->prepare("SELECT * FROM customers WHERE email = ?");
$stmt->execute([$_POST['email']]);
$customer = $stmt->fetch();
if ($customer && password_verify($_POST['password'], $customer['password'])) {
$_SESSION['customer_id'] = $customer['id'];
$_SESSION['customer_name'] = $customer['name'];
header('Location: portal.php');
exit;
} else {
$error_message = 'Invalid email or password.';
}
}
}
?>
<div class="container mt-5">
<div class="row justify-content-center">
<div class="col-md-6">
<div class="card">
<div class="card-body">
<h1 class="card-title text-center mb-4">Customer Login</h1>
<?php if ($error_message): ?>
<div class="alert alert-danger"><?php echo $error_message; ?></div>
<?php endif; ?>
<form method="POST" action="login.php">
<div class="mb-3">
<label for="email" class="form-label">Email Address</label>
<input type="email" id="email" name="email" class="form-control" required>
</div>
<div class="mb-3">
<label for="password" class="form-label">Password</label>
<input type="password" id="password" name="password" class="form-control" required>
</div>
<button type="submit" class="btn btn-primary w-100">Login</button>
</form>
</div>
</div>
</div>
</div>
</div>
<?php include 'footer.php'; ?>

View File

@ -1,6 +0,0 @@
<?php
session_start();
session_unset();
session_destroy();
header('Location: index.php');
exit;

View File

@ -1,116 +0,0 @@
<?php
require_once __DIR__ . '/vendor/autoload.php';
require_once __DIR__ . '/db/config.php';
\Stripe\Stripe::setApiKey('sk_test_51Hh9Y2L9s5P2Q8Z4sYgY8Z4sYgY8Z4sYgY8Z4sYgY8Z4sYgY8Z4sYgY8Z4sYgY8Z4sYgY8Z4sYgY8Z4');
include 'header.php';
$message = '';
$order_details = null;
$error = false;
if (empty($_GET['payment_intent'])) {
$error = true;
$message = "No payment intent provided.";
} else {
$payment_intent_id = $_GET['payment_intent'];
$pdo = db();
try {
// 1. Verify Payment with Stripe
$paymentIntent = \Stripe\PaymentIntent::retrieve($payment_intent_id);
if ($paymentIntent->status == 'succeeded') {
// 2. Find Local Order
$stmt = $pdo->prepare("SELECT * FROM orders WHERE stripe_payment_intent_id = ?");
$stmt->execute([$payment_intent_id]);
$order = $stmt->fetch(PDO::FETCH_OBJ);
if ($order) {
// 3. Update Order Status (if it's still pending)
if ($order->order_status == 'pending') {
$update_stmt = $pdo->prepare("UPDATE orders SET order_status = 'completed' WHERE id = ?");
$update_stmt->execute([$order->id]);
}
// 4. Fetch Order Details for Display
$details_stmt = $pdo->prepare(
"SELECT o.id as order_id, o.amount, c.name as customer_name, c.email, p.name as plan_name
FROM orders o
JOIN customers c ON o.customer_id = c.id
JOIN plans p ON o.plan_id = p.id
WHERE o.id = ?"
);
$details_stmt->execute([$order->id]);
$order_details = $details_stmt->fetch(PDO::FETCH_OBJ);
$message = "Thank you for your order! Your payment was successful.";
// 5. Send Confirmation Email (optional, but good practice)
require_once __DIR__ . '/mail/MailService.php';
$subject = 'Your Australia Broadband Internet Order Confirmation';
$html_body = "<h1>Welcome, " . htmlspecialchars($order_details->customer_name) . "!</h1>"
. "<p>Thank you for your order. Your new internet service is being processed.</p>"
. "<p><strong>Order Details:</strong></p>"
. "<ul>"
. "<li><strong>Order ID:</strong> " . htmlspecialchars($order_details->order_id) . "</li>"
. "<li><strong>Plan:</strong> " . htmlspecialchars($order_details->plan_name) . "</li>"
. "<li><strong>Amount Paid:</strong> $" . htmlspecialchars(number_format($order_details->amount, 2)) . "</li>"
. "</ul>"
. "<p>You will receive further updates from us shortly.</p>";
MailService::sendMail($order_details->email, $subject, $html_body);
} else {
$error = true;
// This is a critical error. Payment succeeded but we can't find the order.
error_log("CRITICAL: Payment succeeded for PI {$payment_intent_id} but no matching order found in DB.");
$message = "Your payment was successful, but we could not find your order. Please contact support immediately.";
}
} else {
$error = true;
$message = "Your payment was not successful. Please try again or contact support.";
}
} catch (Exception $e) {
$error = true;
error_log("Order confirmation error: " . $e->getMessage());
$message = "An error occurred while processing your order. Please contact support.";
}
}
?>
<div class="container mt-5">
<div class="row">
<div class="col-md-8 offset-md-2 text-center">
<?php if ($error): ?>
<div class="alert alert-danger">
<h1 class="alert-heading">Order Error</h1>
<p><?php echo htmlspecialchars($message); ?></p>
</div>
<?php else: ?>
<div class="alert alert-success">
<h1 class="alert-heading">Thank You!</h1>
<p><?php echo htmlspecialchars($message); ?></p>
</div>
<?php if ($order_details): ?>
<div class="card mt-4">
<div class="card-header">
Order Summary
</div>
<div class="card-body">
<p><strong>Order ID:</strong> <?php echo htmlspecialchars($order_details->order_id); ?></p>
<p><strong>Customer:</strong> <?php echo htmlspecialchars($order_details->customer_name); ?></p>
<p><strong>Plan:</strong> <?php echo htmlspecialchars($order_details->plan_name); ?></p>
<p><strong>Amount Paid:</strong> $<?php echo htmlspecialchars(number_format($order_details->amount, 2)); ?></p>
</div>
</div>
<?php endif; ?>
<?php endif; ?>
<a href="/" class="btn btn-primary mt-4">Back to Home</a>
</div>
</div>
</div>
<?php
include 'footer.php';
?>

View File

@ -1,36 +0,0 @@
<?php
require_once 'db/config.php';
$slug = $_GET['slug'] ?? null;
if (!$slug) {
http_response_code(404);
echo "Page not found.";
exit;
}
$stmt = db()->prepare('SELECT * FROM pages WHERE slug = ?');
$stmt->execute([$slug]);
$page = $stmt->fetch();
if (!$page) {
http_response_code(404);
echo "Page not found.";
exit;
}
include 'header.php';
?>
<div class="container mt-5 pt-5">
<div class="row">
<div class="col-lg-10 mx-auto">
<h1 class="display-4 fw-bold text-center"><?php echo htmlspecialchars($page['title']); ?></h1>
<div class="mt-4 fs-5">
<?php echo nl2br(htmlspecialchars($page['content'])); ?>
</div>
</div>
</div>
</div>
<?php include 'footer.php'; ?>

View File

@ -1,26 +0,0 @@
<?php
include 'header.php';
// Protect this page
if (!isset($_SESSION['customer_id'])) {
header('Location: login.php');
exit;
}
?>
<div class="container mt-5">
<div class="row">
<div class="col-md-12">
<div class="card">
<div class="card-body">
<h1 class="card-title">Welcome, <?php echo htmlspecialchars($_SESSION['customer_name']); ?>!</h1>
<p>This is your customer portal. You can view your account details and manage your services here.</p>
<a href="logout.php" class="btn btn-primary">Logout</a>
</div>
</div>
</div>
</div>
</div>
<?php include 'footer.php'; ?>

View File

@ -1,20 +0,0 @@
<?php
// privacy.php
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Privacy Policy - Australia Broadband</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="assets/css/custom.css">
</head>
<body>
<div class="container py-5">
<h1>Privacy Policy</h1>
<p>This is a placeholder for the Privacy Policy page.</p>
<a href="index.php">Back to Home</a>
</div>
</body>
</html>

View File

@ -1,87 +0,0 @@
<?php
require_once __DIR__ . '/db/config.php';
include 'header.php';
if (!isset($_GET['plan_id'])) {
header('Location: /#plans');
exit;
}
$pdo = db();
$stmt = $pdo->prepare("SELECT * FROM plans WHERE id = ?");
$stmt->execute([$_GET['plan_id']]);
$plan = $stmt->fetch();
if (!$plan) {
// Plan not found
header('Location: /#plans');
exit;
}
?>
<div class="container mt-5">
<div class="row">
<div class="col-md-8 offset-md-2">
<h1 class="mb-4">Complete Your Order</h1>
<div class="card mb-4">
<div class="card-body">
<h4 class="card-title">Your Plan</h4>
<h5><?php echo htmlspecialchars($plan['name']); ?></h5>
<p class="price fs-4">$<?php echo htmlspecialchars(number_format($plan['price_monthly'], 2)); ?><span class="period">/mo</span></p>
<p><?php echo htmlspecialchars($plan['description']); ?></p>
</div>
</div>
<h4 class="mb-3">Your Details</h4>
<form id="signup-form" data-plan-id="<?php echo $plan['id']; ?>">
<!-- User details form -->
<div class="mb-3">
<label for="name" class="form-label">Full Name</label>
<input type="text" id="name" class="form-control" required>
</div>
<div class="mb-3">
<label for="email" class="form-label">Email Address</label>
<input type="email" id="email" class="form-control" required>
</div>
<div class="row">
<div class="col-md-6 mb-3">
<label for="password" class="form-label">Password</label>
<input type="password" id="password" class="form-control" required>
</div>
<div class="col-md-6 mb-3">
<label for="password_confirm" class="form-label">Confirm Password</label>
<input type="password" id="password_confirm" class="form-control" required>
</div>
</div>
<div class="mb-3">
<label for="address" class="form-label">Service Address</label>
<input type="text" id="address" class="form-control" required>
</div>
<h4 class="mb-3 mt-4">Payment Details</h4>
<!-- Stripe Payment Element will go here -->
<div id="payment-element" class="mb-3"></div>
<!-- Used to display form errors -->
<div id="payment-message" class="hidden"></div>
<button id="submit" class="btn btn-primary btn-lg w-100">
<span id="button-text">Pay Now</span>
<span id="spinner" style="display: none;">Processing...</span>
</button>
</form>
</div>
</div>
</div>
<script src="https://js.stripe.com/v3/"></script>
<script>
// Pass plan details to JS
const planDetails = {
id: <?php echo json_encode($plan['id']); ?>,
price: <?php echo json_encode($plan['price_monthly']); ?>
};
</script>
<script src="assets/js/signup.js?v=<?php echo time(); ?>"></script>
<?php include 'footer.php'; ?>

View File

@ -1,107 +0,0 @@
<?php include 'header.php'; ?>
<div class="container mt-5">
<div class="row">
<div class="col-md-8 offset-md-2">
<h1 class="text-center mb-4">AI Support Assistant</h1>
<div class="card">
<div class="card-body" id="chat-window" style="height: 400px; overflow-y: scroll;">
<!-- Chat messages will appear here -->
<div class="d-flex flex-row justify-content-start mb-4">
<div class="p-3 ms-3" style="border-radius: 15px; background-color: #f5f6f7;">
<p class="small mb-0">Hello! How can I help you today? Ask me anything about our plans or services.</p>
</div>
</div>
</div>
<div class="card-footer text-muted d-flex justify-content-start align-items-center p-3">
<input type="text" class="form-control form-control-lg" id="user-input" placeholder="Type your message">
<button class="btn btn-primary ms-3" id="send-btn">Send</button>
</div>
</div>
</div>
</div>
</div>
<script>
const chatWindow = document.getElementById('chat-window');
const userInput = document.getElementById('user-input');
const sendBtn = document.getElementById('send-btn');
const addMessage = (message, sender) => {
const messageDiv = document.createElement('div');
const messageContent = document.createElement('div');
const text = document.createElement('p');
messageDiv.classList.add('d-flex', 'flex-row', 'mb-4');
messageContent.classList.add('p-3');
text.classList.add('small', 'mb-0');
text.innerText = message;
messageContent.appendChild(text);
if (sender === 'user') {
messageDiv.classList.add('justify-content-end');
messageContent.classList.add('me-3', 'text-white');
messageContent.style.borderRadius = '15px';
messageContent.style.backgroundColor = '#0d6efd'; // Bootstrap Primary Blue
} else {
messageDiv.classList.add('justify-content-start');
messageContent.classList.add('ms-3');
messageContent.style.borderRadius = '15px';
messageContent.style.backgroundColor = '#f5f6f7'; // Light grey
}
messageDiv.appendChild(messageContent);
chatWindow.appendChild(messageDiv);
chatWindow.scrollTop = chatWindow.scrollHeight; // Auto-scroll to the latest message
};
const handleSend = async () => {
const question = userInput.value.trim();
if (!question) return;
addMessage(question, 'user');
userInput.value = '';
userInput.disabled = true;
sendBtn.disabled = true;
try {
const response = await fetch('/api/ai_support.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ question })
});
if (!response.ok) {
throw new Error('Network response was not ok');
}
const data = await response.json();
if (data.reply) {
addMessage(data.reply, 'ai');
} else if (data.error) {
addMessage(data.error, 'ai');
}
} catch (error) {
console.error('Error:', error);
addMessage('Sorry, something went wrong. Please try again later.', 'ai');
} finally {
userInput.disabled = false;
sendBtn.disabled = false;
userInput.focus();
}
};
sendBtn.addEventListener('click', handleSend);
userInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
handleSend();
}
});
</script>
<?php include 'footer.php'; ?>

22
vendor/autoload.php vendored
View File

@ -1,22 +0,0 @@
<?php
// autoload.php @generated by Composer
if (PHP_VERSION_ID < 50600) {
if (!headers_sent()) {
header('HTTP/1.1 500 Internal Server Error');
}
$err = 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
if (!ini_get('display_errors')) {
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
fwrite(STDERR, $err);
} elseif (!headers_sent()) {
echo $err;
}
}
throw new RuntimeException($err);
}
require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInit4badc292822cc5b9fb20d40b3af3205b::getLoader();

View File

@ -1,579 +0,0 @@
<?php
/*
* This file is part of Composer.
*
* (c) Nils Adermann <naderman@naderman.de>
* Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Composer\Autoload;
/**
* ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
*
* $loader = new \Composer\Autoload\ClassLoader();
*
* // register classes with namespaces
* $loader->add('Symfony\Component', __DIR__.'/component');
* $loader->add('Symfony', __DIR__.'/framework');
*
* // activate the autoloader
* $loader->register();
*
* // to enable searching the include path (eg. for PEAR packages)
* $loader->setUseIncludePath(true);
*
* In this example, if you try to use a class in the Symfony\Component
* namespace or one of its children (Symfony\Component\Console for instance),
* the autoloader will first look for the class under the component/
* directory, and it will then fallback to the framework/ directory if not
* found before giving up.
*
* This class is loosely based on the Symfony UniversalClassLoader.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Jordi Boggiano <j.boggiano@seld.be>
* @see https://www.php-fig.org/psr/psr-0/
* @see https://www.php-fig.org/psr/psr-4/
*/
class ClassLoader
{
/** @var \Closure(string):void */
private static $includeFile;
/** @var string|null */
private $vendorDir;
// PSR-4
/**
* @var array<string, array<string, int>>
*/
private $prefixLengthsPsr4 = array();
/**
* @var array<string, list<string>>
*/
private $prefixDirsPsr4 = array();
/**
* @var list<string>
*/
private $fallbackDirsPsr4 = array();
// PSR-0
/**
* List of PSR-0 prefixes
*
* Structured as array('F (first letter)' => array('Foo\Bar (full prefix)' => array('path', 'path2')))
*
* @var array<string, array<string, list<string>>>
*/
private $prefixesPsr0 = array();
/**
* @var list<string>
*/
private $fallbackDirsPsr0 = array();
/** @var bool */
private $useIncludePath = false;
/**
* @var array<string, string>
*/
private $classMap = array();
/** @var bool */
private $classMapAuthoritative = false;
/**
* @var array<string, bool>
*/
private $missingClasses = array();
/** @var string|null */
private $apcuPrefix;
/**
* @var array<string, self>
*/
private static $registeredLoaders = array();
/**
* @param string|null $vendorDir
*/
public function __construct($vendorDir = null)
{
$this->vendorDir = $vendorDir;
self::initializeIncludeClosure();
}
/**
* @return array<string, list<string>>
*/
public function getPrefixes()
{
if (!empty($this->prefixesPsr0)) {
return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
}
return array();
}
/**
* @return array<string, list<string>>
*/
public function getPrefixesPsr4()
{
return $this->prefixDirsPsr4;
}
/**
* @return list<string>
*/
public function getFallbackDirs()
{
return $this->fallbackDirsPsr0;
}
/**
* @return list<string>
*/
public function getFallbackDirsPsr4()
{
return $this->fallbackDirsPsr4;
}
/**
* @return array<string, string> Array of classname => path
*/
public function getClassMap()
{
return $this->classMap;
}
/**
* @param array<string, string> $classMap Class to filename map
*
* @return void
*/
public function addClassMap(array $classMap)
{
if ($this->classMap) {
$this->classMap = array_merge($this->classMap, $classMap);
} else {
$this->classMap = $classMap;
}
}
/**
* Registers a set of PSR-0 directories for a given prefix, either
* appending or prepending to the ones previously set for this prefix.
*
* @param string $prefix The prefix
* @param list<string>|string $paths The PSR-0 root directories
* @param bool $prepend Whether to prepend the directories
*
* @return void
*/
public function add($prefix, $paths, $prepend = false)
{
$paths = (array) $paths;
if (!$prefix) {
if ($prepend) {
$this->fallbackDirsPsr0 = array_merge(
$paths,
$this->fallbackDirsPsr0
);
} else {
$this->fallbackDirsPsr0 = array_merge(
$this->fallbackDirsPsr0,
$paths
);
}
return;
}
$first = $prefix[0];
if (!isset($this->prefixesPsr0[$first][$prefix])) {
$this->prefixesPsr0[$first][$prefix] = $paths;
return;
}
if ($prepend) {
$this->prefixesPsr0[$first][$prefix] = array_merge(
$paths,
$this->prefixesPsr0[$first][$prefix]
);
} else {
$this->prefixesPsr0[$first][$prefix] = array_merge(
$this->prefixesPsr0[$first][$prefix],
$paths
);
}
}
/**
* Registers a set of PSR-4 directories for a given namespace, either
* appending or prepending to the ones previously set for this namespace.
*
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param list<string>|string $paths The PSR-4 base directories
* @param bool $prepend Whether to prepend the directories
*
* @throws \InvalidArgumentException
*
* @return void
*/
public function addPsr4($prefix, $paths, $prepend = false)
{
$paths = (array) $paths;
if (!$prefix) {
// Register directories for the root namespace.
if ($prepend) {
$this->fallbackDirsPsr4 = array_merge(
$paths,
$this->fallbackDirsPsr4
);
} else {
$this->fallbackDirsPsr4 = array_merge(
$this->fallbackDirsPsr4,
$paths
);
}
} elseif (!isset($this->prefixDirsPsr4[$prefix])) {
// Register directories for a new namespace.
$length = strlen($prefix);
if ('\\' !== $prefix[$length - 1]) {
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
}
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
$this->prefixDirsPsr4[$prefix] = $paths;
} elseif ($prepend) {
// Prepend directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge(
$paths,
$this->prefixDirsPsr4[$prefix]
);
} else {
// Append directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge(
$this->prefixDirsPsr4[$prefix],
$paths
);
}
}
/**
* Registers a set of PSR-0 directories for a given prefix,
* replacing any others previously set for this prefix.
*
* @param string $prefix The prefix
* @param list<string>|string $paths The PSR-0 base directories
*
* @return void
*/
public function set($prefix, $paths)
{
if (!$prefix) {
$this->fallbackDirsPsr0 = (array) $paths;
} else {
$this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
}
}
/**
* Registers a set of PSR-4 directories for a given namespace,
* replacing any others previously set for this namespace.
*
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param list<string>|string $paths The PSR-4 base directories
*
* @throws \InvalidArgumentException
*
* @return void
*/
public function setPsr4($prefix, $paths)
{
if (!$prefix) {
$this->fallbackDirsPsr4 = (array) $paths;
} else {
$length = strlen($prefix);
if ('\\' !== $prefix[$length - 1]) {
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
}
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
$this->prefixDirsPsr4[$prefix] = (array) $paths;
}
}
/**
* Turns on searching the include path for class files.
*
* @param bool $useIncludePath
*
* @return void
*/
public function setUseIncludePath($useIncludePath)
{
$this->useIncludePath = $useIncludePath;
}
/**
* Can be used to check if the autoloader uses the include path to check
* for classes.
*
* @return bool
*/
public function getUseIncludePath()
{
return $this->useIncludePath;
}
/**
* Turns off searching the prefix and fallback directories for classes
* that have not been registered with the class map.
*
* @param bool $classMapAuthoritative
*
* @return void
*/
public function setClassMapAuthoritative($classMapAuthoritative)
{
$this->classMapAuthoritative = $classMapAuthoritative;
}
/**
* Should class lookup fail if not found in the current class map?
*
* @return bool
*/
public function isClassMapAuthoritative()
{
return $this->classMapAuthoritative;
}
/**
* APCu prefix to use to cache found/not-found classes, if the extension is enabled.
*
* @param string|null $apcuPrefix
*
* @return void
*/
public function setApcuPrefix($apcuPrefix)
{
$this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
}
/**
* The APCu prefix in use, or null if APCu caching is not enabled.
*
* @return string|null
*/
public function getApcuPrefix()
{
return $this->apcuPrefix;
}
/**
* Registers this instance as an autoloader.
*
* @param bool $prepend Whether to prepend the autoloader or not
*
* @return void
*/
public function register($prepend = false)
{
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
if (null === $this->vendorDir) {
return;
}
if ($prepend) {
self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
} else {
unset(self::$registeredLoaders[$this->vendorDir]);
self::$registeredLoaders[$this->vendorDir] = $this;
}
}
/**
* Unregisters this instance as an autoloader.
*
* @return void
*/
public function unregister()
{
spl_autoload_unregister(array($this, 'loadClass'));
if (null !== $this->vendorDir) {
unset(self::$registeredLoaders[$this->vendorDir]);
}
}
/**
* Loads the given class or interface.
*
* @param string $class The name of the class
* @return true|null True if loaded, null otherwise
*/
public function loadClass($class)
{
if ($file = $this->findFile($class)) {
$includeFile = self::$includeFile;
$includeFile($file);
return true;
}
return null;
}
/**
* Finds the path to the file where the class is defined.
*
* @param string $class The name of the class
*
* @return string|false The path if found, false otherwise
*/
public function findFile($class)
{
// class map lookup
if (isset($this->classMap[$class])) {
return $this->classMap[$class];
}
if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
return false;
}
if (null !== $this->apcuPrefix) {
$file = apcu_fetch($this->apcuPrefix.$class, $hit);
if ($hit) {
return $file;
}
}
$file = $this->findFileWithExtension($class, '.php');
// Search for Hack files if we are running on HHVM
if (false === $file && defined('HHVM_VERSION')) {
$file = $this->findFileWithExtension($class, '.hh');
}
if (null !== $this->apcuPrefix) {
apcu_add($this->apcuPrefix.$class, $file);
}
if (false === $file) {
// Remember that this class does not exist.
$this->missingClasses[$class] = true;
}
return $file;
}
/**
* Returns the currently registered loaders keyed by their corresponding vendor directories.
*
* @return array<string, self>
*/
public static function getRegisteredLoaders()
{
return self::$registeredLoaders;
}
/**
* @param string $class
* @param string $ext
* @return string|false
*/
private function findFileWithExtension($class, $ext)
{
// PSR-4 lookup
$logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
$first = $class[0];
if (isset($this->prefixLengthsPsr4[$first])) {
$subPath = $class;
while (false !== $lastPos = strrpos($subPath, '\\')) {
$subPath = substr($subPath, 0, $lastPos);
$search = $subPath . '\\';
if (isset($this->prefixDirsPsr4[$search])) {
$pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
foreach ($this->prefixDirsPsr4[$search] as $dir) {
if (file_exists($file = $dir . $pathEnd)) {
return $file;
}
}
}
}
}
// PSR-4 fallback dirs
foreach ($this->fallbackDirsPsr4 as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
return $file;
}
}
// PSR-0 lookup
if (false !== $pos = strrpos($class, '\\')) {
// namespaced class name
$logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
. strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
} else {
// PEAR-like class name
$logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
}
if (isset($this->prefixesPsr0[$first])) {
foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
if (0 === strpos($class, $prefix)) {
foreach ($dirs as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
return $file;
}
}
}
}
}
// PSR-0 fallback dirs
foreach ($this->fallbackDirsPsr0 as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
return $file;
}
}
// PSR-0 include paths.
if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
return $file;
}
return false;
}
/**
* @return void
*/
private static function initializeIncludeClosure()
{
if (self::$includeFile !== null) {
return;
}
/**
* Scope isolated include.
*
* Prevents access to $this/self from included files.
*
* @param string $file
* @return void
*/
self::$includeFile = \Closure::bind(static function($file) {
include $file;
}, null, null);
}
}

View File

@ -1,396 +0,0 @@
<?php
/*
* This file is part of Composer.
*
* (c) Nils Adermann <naderman@naderman.de>
* Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Composer;
use Composer\Autoload\ClassLoader;
use Composer\Semver\VersionParser;
/**
* This class is copied in every Composer installed project and available to all
*
* See also https://getcomposer.org/doc/07-runtime.md#installed-versions
*
* To require its presence, you can require `composer-runtime-api ^2.0`
*
* @final
*/
class InstalledVersions
{
/**
* @var string|null if set (by reflection by Composer), this should be set to the path where this class is being copied to
* @internal
*/
private static $selfDir = null;
/**
* @var mixed[]|null
* @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null
*/
private static $installed;
/**
* @var bool
*/
private static $installedIsLocalDir;
/**
* @var bool|null
*/
private static $canGetVendors;
/**
* @var array[]
* @psalm-var array<string, array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
*/
private static $installedByVendor = array();
/**
* Returns a list of all package names which are present, either by being installed, replaced or provided
*
* @return string[]
* @psalm-return list<string>
*/
public static function getInstalledPackages()
{
$packages = array();
foreach (self::getInstalled() as $installed) {
$packages[] = array_keys($installed['versions']);
}
if (1 === \count($packages)) {
return $packages[0];
}
return array_keys(array_flip(\call_user_func_array('array_merge', $packages)));
}
/**
* Returns a list of all package names with a specific type e.g. 'library'
*
* @param string $type
* @return string[]
* @psalm-return list<string>
*/
public static function getInstalledPackagesByType($type)
{
$packagesByType = array();
foreach (self::getInstalled() as $installed) {
foreach ($installed['versions'] as $name => $package) {
if (isset($package['type']) && $package['type'] === $type) {
$packagesByType[] = $name;
}
}
}
return $packagesByType;
}
/**
* Checks whether the given package is installed
*
* This also returns true if the package name is provided or replaced by another package
*
* @param string $packageName
* @param bool $includeDevRequirements
* @return bool
*/
public static function isInstalled($packageName, $includeDevRequirements = true)
{
foreach (self::getInstalled() as $installed) {
if (isset($installed['versions'][$packageName])) {
return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false;
}
}
return false;
}
/**
* Checks whether the given package satisfies a version constraint
*
* e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call:
*
* Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3')
*
* @param VersionParser $parser Install composer/semver to have access to this class and functionality
* @param string $packageName
* @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package
* @return bool
*/
public static function satisfies(VersionParser $parser, $packageName, $constraint)
{
$constraint = $parser->parseConstraints((string) $constraint);
$provided = $parser->parseConstraints(self::getVersionRanges($packageName));
return $provided->matches($constraint);
}
/**
* Returns a version constraint representing all the range(s) which are installed for a given package
*
* It is easier to use this via isInstalled() with the $constraint argument if you need to check
* whether a given version of a package is installed, and not just whether it exists
*
* @param string $packageName
* @return string Version constraint usable with composer/semver
*/
public static function getVersionRanges($packageName)
{
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
continue;
}
$ranges = array();
if (isset($installed['versions'][$packageName]['pretty_version'])) {
$ranges[] = $installed['versions'][$packageName]['pretty_version'];
}
if (array_key_exists('aliases', $installed['versions'][$packageName])) {
$ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']);
}
if (array_key_exists('replaced', $installed['versions'][$packageName])) {
$ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']);
}
if (array_key_exists('provided', $installed['versions'][$packageName])) {
$ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']);
}
return implode(' || ', $ranges);
}
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
/**
* @param string $packageName
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
*/
public static function getVersion($packageName)
{
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
continue;
}
if (!isset($installed['versions'][$packageName]['version'])) {
return null;
}
return $installed['versions'][$packageName]['version'];
}
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
/**
* @param string $packageName
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
*/
public static function getPrettyVersion($packageName)
{
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
continue;
}
if (!isset($installed['versions'][$packageName]['pretty_version'])) {
return null;
}
return $installed['versions'][$packageName]['pretty_version'];
}
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
/**
* @param string $packageName
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference
*/
public static function getReference($packageName)
{
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
continue;
}
if (!isset($installed['versions'][$packageName]['reference'])) {
return null;
}
return $installed['versions'][$packageName]['reference'];
}
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
/**
* @param string $packageName
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path.
*/
public static function getInstallPath($packageName)
{
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
continue;
}
return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null;
}
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
/**
* @return array
* @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}
*/
public static function getRootPackage()
{
$installed = self::getInstalled();
return $installed[0]['root'];
}
/**
* Returns the raw installed.php data for custom implementations
*
* @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
* @return array[]
* @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}
*/
public static function getRawData()
{
@trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED);
if (null === self::$installed) {
// only require the installed.php file if this file is loaded from its dumped location,
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
if (substr(__DIR__, -8, 1) !== 'C') {
self::$installed = include __DIR__ . '/installed.php';
} else {
self::$installed = array();
}
}
return self::$installed;
}
/**
* Returns the raw data of all installed.php which are currently loaded for custom implementations
*
* @return array[]
* @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
*/
public static function getAllRawData()
{
return self::getInstalled();
}
/**
* Lets you reload the static array from another file
*
* This is only useful for complex integrations in which a project needs to use
* this class but then also needs to execute another project's autoloader in process,
* and wants to ensure both projects have access to their version of installed.php.
*
* A typical case would be PHPUnit, where it would need to make sure it reads all
* the data it needs from this class, then call reload() with
* `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure
* the project in which it runs can then also use this class safely, without
* interference between PHPUnit's dependencies and the project's dependencies.
*
* @param array[] $data A vendor/composer/installed.php data set
* @return void
*
* @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $data
*/
public static function reload($data)
{
self::$installed = $data;
self::$installedByVendor = array();
// when using reload, we disable the duplicate protection to ensure that self::$installed data is
// always returned, but we cannot know whether it comes from the installed.php in __DIR__ or not,
// so we have to assume it does not, and that may result in duplicate data being returned when listing
// all installed packages for example
self::$installedIsLocalDir = false;
}
/**
* @return string
*/
private static function getSelfDir()
{
if (self::$selfDir === null) {
self::$selfDir = strtr(__DIR__, '\\', '/');
}
return self::$selfDir;
}
/**
* @return array[]
* @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
*/
private static function getInstalled()
{
if (null === self::$canGetVendors) {
self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders');
}
$installed = array();
$copiedLocalDir = false;
if (self::$canGetVendors) {
$selfDir = self::getSelfDir();
foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
$vendorDir = strtr($vendorDir, '\\', '/');
if (isset(self::$installedByVendor[$vendorDir])) {
$installed[] = self::$installedByVendor[$vendorDir];
} elseif (is_file($vendorDir.'/composer/installed.php')) {
/** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
$required = require $vendorDir.'/composer/installed.php';
self::$installedByVendor[$vendorDir] = $required;
$installed[] = $required;
if (self::$installed === null && $vendorDir.'/composer' === $selfDir) {
self::$installed = $required;
self::$installedIsLocalDir = true;
}
}
if (self::$installedIsLocalDir && $vendorDir.'/composer' === $selfDir) {
$copiedLocalDir = true;
}
}
}
if (null === self::$installed) {
// only require the installed.php file if this file is loaded from its dumped location,
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
if (substr(__DIR__, -8, 1) !== 'C') {
/** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
$required = require __DIR__ . '/installed.php';
self::$installed = $required;
} else {
self::$installed = array();
}
}
if (self::$installed !== array() && !$copiedLocalDir) {
$installed[] = self::$installed;
}
return $installed;
}
}

View File

@ -1,21 +0,0 @@
Copyright (c) Nils Adermann, Jordi Boggiano
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@ -1,35 +0,0 @@
<?php
// autoload_classmap.php @generated by Composer
$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);
return array(
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
'Stripe' => $vendorDir . '/stripe/stripe-php/lib/Stripe/Stripe.php',
'Stripe_Account' => $vendorDir . '/stripe/stripe-php/lib/Stripe/Account.php',
'Stripe_ApiConnectionError' => $vendorDir . '/stripe/stripe-php/lib/Stripe/ApiConnectionError.php',
'Stripe_ApiError' => $vendorDir . '/stripe/stripe-php/lib/Stripe/ApiError.php',
'Stripe_ApiRequestor' => $vendorDir . '/stripe/stripe-php/lib/Stripe/ApiRequestor.php',
'Stripe_ApiResource' => $vendorDir . '/stripe/stripe-php/lib/Stripe/ApiResource.php',
'Stripe_AuthenticationError' => $vendorDir . '/stripe/stripe-php/lib/Stripe/AuthenticationError.php',
'Stripe_CardError' => $vendorDir . '/stripe/stripe-php/lib/Stripe/CardError.php',
'Stripe_Charge' => $vendorDir . '/stripe/stripe-php/lib/Stripe/Charge.php',
'Stripe_Coupon' => $vendorDir . '/stripe/stripe-php/lib/Stripe/Coupon.php',
'Stripe_Customer' => $vendorDir . '/stripe/stripe-php/lib/Stripe/Customer.php',
'Stripe_Error' => $vendorDir . '/stripe/stripe-php/lib/Stripe/Error.php',
'Stripe_Event' => $vendorDir . '/stripe/stripe-php/lib/Stripe/Event.php',
'Stripe_InvalidRequestError' => $vendorDir . '/stripe/stripe-php/lib/Stripe/InvalidRequestError.php',
'Stripe_Invoice' => $vendorDir . '/stripe/stripe-php/lib/Stripe/Invoice.php',
'Stripe_InvoiceItem' => $vendorDir . '/stripe/stripe-php/lib/Stripe/InvoiceItem.php',
'Stripe_List' => $vendorDir . '/stripe/stripe-php/lib/Stripe/List.php',
'Stripe_Object' => $vendorDir . '/stripe/stripe-php/lib/Stripe/Object.php',
'Stripe_Plan' => $vendorDir . '/stripe/stripe-php/lib/Stripe/Plan.php',
'Stripe_Recipient' => $vendorDir . '/stripe/stripe-php/lib/Stripe/Recipient.php',
'Stripe_SingletonApiResource' => $vendorDir . '/stripe/stripe-php/lib/Stripe/SingletonApiResource.php',
'Stripe_Token' => $vendorDir . '/stripe/stripe-php/lib/Stripe/Token.php',
'Stripe_Transfer' => $vendorDir . '/stripe/stripe-php/lib/Stripe/Transfer.php',
'Stripe_Util' => $vendorDir . '/stripe/stripe-php/lib/Stripe/Util.php',
'Stripe_Util_Set' => $vendorDir . '/stripe/stripe-php/lib/Stripe/Util/Set.php',
);

View File

@ -1,9 +0,0 @@
<?php
// autoload_namespaces.php @generated by Composer
$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);
return array(
);

View File

@ -1,9 +0,0 @@
<?php
// autoload_psr4.php @generated by Composer
$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);
return array(
);

View File

@ -1,38 +0,0 @@
<?php
// autoload_real.php @generated by Composer
class ComposerAutoloaderInit4badc292822cc5b9fb20d40b3af3205b
{
private static $loader;
public static function loadClassLoader($class)
{
if ('Composer\Autoload\ClassLoader' === $class) {
require __DIR__ . '/ClassLoader.php';
}
}
/**
* @return \Composer\Autoload\ClassLoader
*/
public static function getLoader()
{
if (null !== self::$loader) {
return self::$loader;
}
require __DIR__ . '/platform_check.php';
spl_autoload_register(array('ComposerAutoloaderInit4badc292822cc5b9fb20d40b3af3205b', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
spl_autoload_unregister(array('ComposerAutoloaderInit4badc292822cc5b9fb20d40b3af3205b', 'loadClassLoader'));
require __DIR__ . '/autoload_static.php';
call_user_func(\Composer\Autoload\ComposerStaticInit4badc292822cc5b9fb20d40b3af3205b::getInitializer($loader));
$loader->register(true);
return $loader;
}
}

View File

@ -1,45 +0,0 @@
<?php
// autoload_static.php @generated by Composer
namespace Composer\Autoload;
class ComposerStaticInit4badc292822cc5b9fb20d40b3af3205b
{
public static $classMap = array (
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
'Stripe' => __DIR__ . '/..' . '/stripe/stripe-php/lib/Stripe/Stripe.php',
'Stripe_Account' => __DIR__ . '/..' . '/stripe/stripe-php/lib/Stripe/Account.php',
'Stripe_ApiConnectionError' => __DIR__ . '/..' . '/stripe/stripe-php/lib/Stripe/ApiConnectionError.php',
'Stripe_ApiError' => __DIR__ . '/..' . '/stripe/stripe-php/lib/Stripe/ApiError.php',
'Stripe_ApiRequestor' => __DIR__ . '/..' . '/stripe/stripe-php/lib/Stripe/ApiRequestor.php',
'Stripe_ApiResource' => __DIR__ . '/..' . '/stripe/stripe-php/lib/Stripe/ApiResource.php',
'Stripe_AuthenticationError' => __DIR__ . '/..' . '/stripe/stripe-php/lib/Stripe/AuthenticationError.php',
'Stripe_CardError' => __DIR__ . '/..' . '/stripe/stripe-php/lib/Stripe/CardError.php',
'Stripe_Charge' => __DIR__ . '/..' . '/stripe/stripe-php/lib/Stripe/Charge.php',
'Stripe_Coupon' => __DIR__ . '/..' . '/stripe/stripe-php/lib/Stripe/Coupon.php',
'Stripe_Customer' => __DIR__ . '/..' . '/stripe/stripe-php/lib/Stripe/Customer.php',
'Stripe_Error' => __DIR__ . '/..' . '/stripe/stripe-php/lib/Stripe/Error.php',
'Stripe_Event' => __DIR__ . '/..' . '/stripe/stripe-php/lib/Stripe/Event.php',
'Stripe_InvalidRequestError' => __DIR__ . '/..' . '/stripe/stripe-php/lib/Stripe/InvalidRequestError.php',
'Stripe_Invoice' => __DIR__ . '/..' . '/stripe/stripe-php/lib/Stripe/Invoice.php',
'Stripe_InvoiceItem' => __DIR__ . '/..' . '/stripe/stripe-php/lib/Stripe/InvoiceItem.php',
'Stripe_List' => __DIR__ . '/..' . '/stripe/stripe-php/lib/Stripe/List.php',
'Stripe_Object' => __DIR__ . '/..' . '/stripe/stripe-php/lib/Stripe/Object.php',
'Stripe_Plan' => __DIR__ . '/..' . '/stripe/stripe-php/lib/Stripe/Plan.php',
'Stripe_Recipient' => __DIR__ . '/..' . '/stripe/stripe-php/lib/Stripe/Recipient.php',
'Stripe_SingletonApiResource' => __DIR__ . '/..' . '/stripe/stripe-php/lib/Stripe/SingletonApiResource.php',
'Stripe_Token' => __DIR__ . '/..' . '/stripe/stripe-php/lib/Stripe/Token.php',
'Stripe_Transfer' => __DIR__ . '/..' . '/stripe/stripe-php/lib/Stripe/Transfer.php',
'Stripe_Util' => __DIR__ . '/..' . '/stripe/stripe-php/lib/Stripe/Util.php',
'Stripe_Util_Set' => __DIR__ . '/..' . '/stripe/stripe-php/lib/Stripe/Util/Set.php',
);
public static function getInitializer(ClassLoader $loader)
{
return \Closure::bind(function () use ($loader) {
$loader->classMap = ComposerStaticInit4badc292822cc5b9fb20d40b3af3205b::$classMap;
}, null, ClassLoader::class);
}
}

View File

@ -1,59 +0,0 @@
{
"packages": [
{
"name": "stripe/stripe-php",
"version": "v1.8.0",
"version_normalized": "1.8.0.0",
"source": {
"type": "git",
"url": "https://github.com/stripe/stripe-php.git",
"reference": "5eba614baf4adefffdd59d196679a16d7baf70da"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/stripe/stripe-php/zipball/5eba614baf4adefffdd59d196679a16d7baf70da",
"reference": "5eba614baf4adefffdd59d196679a16d7baf70da",
"shasum": ""
},
"require": {
"ext-curl": "*",
"php": ">=5.2"
},
"require-dev": {
"vierbergenlars/simpletest": "*"
},
"time": "2013-04-12T18:56:41+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"classmap": [
"lib/Stripe/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Stripe and contributors",
"homepage": "https://github.com/stripe/stripe-php/contributors"
}
],
"description": "Stripe PHP Library",
"homepage": "https://stripe.com/",
"keywords": [
"api",
"payment processing",
"stripe"
],
"support": {
"issues": "https://github.com/stripe/stripe-php/issues",
"source": "https://github.com/stripe/stripe-php/tree/transfers-recipients"
},
"install-path": "../stripe/stripe-php"
}
],
"dev": true,
"dev-package-names": []
}

View File

@ -1,32 +0,0 @@
<?php return array(
'root' => array(
'name' => 'flatlogic/customer-project',
'pretty_version' => 'dev-master',
'version' => 'dev-master',
'reference' => 'b29f71a77323569c4ea1b072b00995babc99f322',
'type' => 'library',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
'dev' => true,
),
'versions' => array(
'flatlogic/customer-project' => array(
'pretty_version' => 'dev-master',
'version' => 'dev-master',
'reference' => 'b29f71a77323569c4ea1b072b00995babc99f322',
'type' => 'library',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
'dev_requirement' => false,
),
'stripe/stripe-php' => array(
'pretty_version' => 'v1.8.0',
'version' => '1.8.0.0',
'reference' => '5eba614baf4adefffdd59d196679a16d7baf70da',
'type' => 'library',
'install_path' => __DIR__ . '/../stripe/stripe-php',
'aliases' => array(),
'dev_requirement' => false,
),
),
);

View File

@ -1,25 +0,0 @@
<?php
// platform_check.php @generated by Composer
$issues = array();
if (!(PHP_VERSION_ID >= 50200)) {
$issues[] = 'Your Composer dependencies require a PHP version ">= 5.2.0". You are running ' . PHP_VERSION . '.';
}
if ($issues) {
if (!headers_sent()) {
header('HTTP/1.1 500 Internal Server Error');
}
if (!ini_get('display_errors')) {
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL);
} elseif (!headers_sent()) {
echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL;
}
}
throw new \RuntimeException(
'Composer detected issues in your platform: ' . implode(' ', $issues)
);
}

View File

@ -1,11 +0,0 @@
# Mac OS X dumps these all over the place.
.DS_Store
# Ignore the SimpleTest library if it is installed to /test/.
/test/simpletest/
# Ignore the /vendor/ directory for people using composer
/vendor/
# If the vendor directory isn't being commited the composer.lock file should also be ignored
composer.lock

View File

@ -1,9 +0,0 @@
language: php
php:
- 5.2
- 5.3
- 5.4
before_script:
- wget http://voxel.dl.sourceforge.net/project/simpletest/simpletest/simpletest_1.1/simpletest_1.1.0.tar.gz
- tar xf simpletest_1.1.0.tar.gz -C test
script: php test/Stripe.php

View File

@ -1,96 +0,0 @@
=== 1.8.0 2013-04-11
* Allow Transfers to be creatable
* Add new Recipient resource
=== 1.7.15 2013-02-21
* Add 'id' to the list of permanent object attributes
=== 1.7.14 2013-02-20
* Don't re-encode strings that are already encoded in UTF-8. If you
were previously using plan or coupon objects with UTF-8 IDs, they
may have been treated as ISO-8859-1 (Latin-1) and encoded to UTF-8 a
2nd time. You may now need to pass the IDs to utf8_encode before
passing them to Stripe_Plan::retrieve or Stripe_Coupon::retrieve.
* Ensure that all input is encoded in UTF-8 before submitting it to
Stripe's servers. (github issue #27)
=== 1.7.13 2013-02-01
* Add support for passing options when retrieving Stripe objects
e.g., Stripe_Charge::retrieve(array("id"=>"foo", "expand" => array("customer")))
Stripe_Charge::retrieve("foo") will continue to work
=== 1.7.12 2013-01-15
* Add support for setting a Stripe API version override
=== 1.7.11 2012-12-30
* Version bump to cleanup constants and such (github issue #26)
=== 1.7.10 2012-11-08
* Add support for updating charge disputes.
* Fix bug preventing retrieval of null attributes
=== 1.7.9 2012-11-08
* Fix usage under autoloaders such as the one generated by composer
(github issue #22)
=== 1.7.8 2012-10-30
* Add support for creating invoices.
* Add support for new invoice lines return format
* Add support for new list objects
=== 1.7.7 2012-09-14
* Get all of the various version numbers in the repo in sync (no other
changes)
=== 1.7.6 2012-08-31
* Add update and pay methods to Invoice resource
=== 1.7.5 2012-08-23
* Change internal function names so that Stripe_SingletonApiRequst is
E_STRICT-clean (github issue #16)
=== 1.7.4 2012-08-21
* Bugfix so that Stripe objects (e.g. Customer, Charge objects) used
in API calls are transparently converted to their object IDs
=== 1.7.3 2012-08-15
* Add new Account resource
=== 1.7.2 2012-06-26
* Make clearer that you should be including lib/Stripe.php, not
test/Stripe.php (github issue #14)
=== 1.7.1 2012-05-24
* Add missing argument to Stripe_InvalidRequestError constructor in
Stripe_ApiResource::instanceUrl. Fixes a warning when
Stripe_ApiResource::instanceUrl is called on a resouce with no ID
(github issue #12)
=== 1.7.0 2012-05-17
* Support Composer and Packagist (github issue #9)
* Add new deleteDiscount method to Stripe_Customer
* Add new Transfer resource
* Switch from using HTTP Basic auth to Bearer auth. (Note: Stripe will
support Basic auth for the indefinite future, but recommends Bearer
auth when possible going forward)
* Numerous test suite improvements

View File

@ -1,21 +0,0 @@
The MIT License
Copyright (c) 2010 Stripe
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@ -1,30 +0,0 @@
= Installation
Obtain the latest version of the Stripe PHP bindings with:
git clone https://github.com/stripe/stripe-php
To get started, add the following to your PHP script:
require_once("/path/to/stripe-php/lib/Stripe.php");
Simple usage looks like:
Stripe::setApiKey('d8e8fca2dc0f896fd7cb4cb0031ba249');
$myCard = array('number' => '4242424242424242', 'exp_month' => 5, 'exp_year' => 2015);
$charge = Stripe_Charge::create(array('card' => $myCard, 'amount' => 2000, 'currency' => 'usd'));
echo $charge;
= Documentation
Please see https://stripe.com/api for up-to-date documentation.
= Tests
In order to run tests you have to install SimpleTest (http://packagist.org/packages/vierbergenlars/simpletest) via Composer (http://getcomposer.org/) (recommended way):
composer.phar update --dev
Run test suite:
php ./test/Stripe.php

View File

@ -1 +0,0 @@
1.8.0

View File

@ -1,27 +0,0 @@
{
"name": "stripe/stripe-php",
"description": "Stripe PHP Library",
"keywords": [
"stripe",
"payment processing",
"api"
],
"homepage": "https://stripe.com/",
"license": "MIT",
"authors": [
{
"name": "Stripe and contributors",
"homepage": "https://github.com/stripe/stripe-php/contributors"
}
],
"require": {
"php": ">=5.2",
"ext-curl": "*"
},
"require-dev": {
"vierbergenlars/simpletest": "*"
},
"autoload": {
"classmap": ["lib/Stripe/"]
}
}

View File

@ -1,46 +0,0 @@
<?php
// Tested on PHP 5.2, 5.3
// This snippet (and some of the curl code) due to the Facebook SDK.
if (!function_exists('curl_init')) {
throw new Exception('Stripe needs the CURL PHP extension.');
}
if (!function_exists('json_decode')) {
throw new Exception('Stripe needs the JSON PHP extension.');
}
// Stripe singleton
require(dirname(__FILE__) . '/Stripe/Stripe.php');
// Utilities
require(dirname(__FILE__) . '/Stripe/Util.php');
require(dirname(__FILE__) . '/Stripe/Util/Set.php');
// Errors
require(dirname(__FILE__) . '/Stripe/Error.php');
require(dirname(__FILE__) . '/Stripe/ApiError.php');
require(dirname(__FILE__) . '/Stripe/ApiConnectionError.php');
require(dirname(__FILE__) . '/Stripe/AuthenticationError.php');
require(dirname(__FILE__) . '/Stripe/CardError.php');
require(dirname(__FILE__) . '/Stripe/InvalidRequestError.php');
// Plumbing
require(dirname(__FILE__) . '/Stripe/Object.php');
require(dirname(__FILE__) . '/Stripe/ApiRequestor.php');
require(dirname(__FILE__) . '/Stripe/ApiResource.php');
require(dirname(__FILE__) . '/Stripe/SingletonApiResource.php');
require(dirname(__FILE__) . '/Stripe/List.php');
// Stripe API Resources
require(dirname(__FILE__) . '/Stripe/Account.php');
require(dirname(__FILE__) . '/Stripe/Charge.php');
require(dirname(__FILE__) . '/Stripe/Customer.php');
require(dirname(__FILE__) . '/Stripe/Invoice.php');
require(dirname(__FILE__) . '/Stripe/InvoiceItem.php');
require(dirname(__FILE__) . '/Stripe/Plan.php');
require(dirname(__FILE__) . '/Stripe/Token.php');
require(dirname(__FILE__) . '/Stripe/Coupon.php');
require(dirname(__FILE__) . '/Stripe/Event.php');
require(dirname(__FILE__) . '/Stripe/Transfer.php');
require(dirname(__FILE__) . '/Stripe/Recipient.php');

View File

@ -1,16 +0,0 @@
<?php
class Stripe_Account extends Stripe_SingletonApiResource
{
public static function constructFrom($values, $apiKey=null)
{
$class = get_class();
return self::scopedConstructFrom($class, $values, $apiKey);
}
public static function retrieve($apiKey=null)
{
$class = get_class();
return self::_scopedSingletonRetrieve($class, $apiKey);
}
}

View File

@ -1,5 +0,0 @@
<?php
class Stripe_ApiConnectionError extends Stripe_Error
{
}

View File

@ -1,5 +0,0 @@
<?php
class Stripe_ApiError extends Stripe_Error
{
}

View File

@ -1,222 +0,0 @@
<?php
class Stripe_ApiRequestor
{
public $apiKey;
public function __construct($apiKey=null)
{
$this->_apiKey = $apiKey;
}
public static function apiUrl($url='')
{
$apiBase = Stripe::$apiBase;
return "$apiBase$url";
}
public static function utf8($value)
{
if (is_string($value) && mb_detect_encoding($value, "UTF-8", TRUE) != "UTF-8")
return utf8_encode($value);
else
return $value;
}
private static function _encodeObjects($d)
{
if ($d instanceof Stripe_ApiResource) {
return self::utf8($d->id);
} else if ($d === true) {
return 'true';
} else if ($d === false) {
return 'false';
} else if (is_array($d)) {
$res = array();
foreach ($d as $k => $v)
$res[$k] = self::_encodeObjects($v);
return $res;
} else {
return self::utf8($d);
}
}
public static function encode($arr, $prefix=null)
{
if (!is_array($arr))
return $arr;
$r = array();
foreach ($arr as $k => $v) {
if (is_null($v))
continue;
if ($prefix && $k && !is_int($k))
$k = $prefix."[".$k."]";
else if ($prefix)
$k = $prefix."[]";
if (is_array($v)) {
$r[] = self::encode($v, $k, true);
} else {
$r[] = urlencode($k)."=".urlencode($v);
}
}
return implode("&", $r);
}
public function request($meth, $url, $params=null)
{
if (!$params)
$params = array();
list($rbody, $rcode, $myApiKey) = $this->_requestRaw($meth, $url, $params);
$resp = $this->_interpretResponse($rbody, $rcode);
return array($resp, $myApiKey);
}
public function handleApiError($rbody, $rcode, $resp)
{
if (!is_array($resp) || !isset($resp['error']))
throw new Stripe_ApiError("Invalid response object from API: $rbody (HTTP response code was $rcode)", $rcode, $rbody, $resp);
$error = $resp['error'];
switch ($rcode) {
case 400:
case 404:
throw new Stripe_InvalidRequestError(isset($error['message']) ? $error['message'] : null,
isset($error['param']) ? $error['param'] : null,
$rcode, $rbody, $resp);
case 401:
throw new Stripe_AuthenticationError(isset($error['message']) ? $error['message'] : null, $rcode, $rbody, $resp);
case 402:
throw new Stripe_CardError(isset($error['message']) ? $error['message'] : null,
isset($error['param']) ? $error['param'] : null,
isset($error['code']) ? $error['code'] : null,
$rcode, $rbody, $resp);
default:
throw new Stripe_ApiError(isset($error['message']) ? $error['message'] : null, $rcode, $rbody, $resp);
}
}
private function _requestRaw($meth, $url, $params)
{
$myApiKey = $this->_apiKey;
if (!$myApiKey)
$myApiKey = Stripe::$apiKey;
if (!$myApiKey)
throw new Stripe_AuthenticationError('No API key provided. (HINT: set your API key using "Stripe::setApiKey(<API-KEY>)". You can generate API keys from the Stripe web interface. See https://stripe.com/api for details, or email support@stripe.com if you have any questions.');
$absUrl = $this->apiUrl($url);
$params = self::_encodeObjects($params);
$langVersion = phpversion();
$uname = php_uname();
$ua = array('bindings_version' => Stripe::VERSION,
'lang' => 'php',
'lang_version' => $langVersion,
'publisher' => 'stripe',
'uname' => $uname);
$headers = array('X-Stripe-Client-User-Agent: ' . json_encode($ua),
'User-Agent: Stripe/v1 PhpBindings/' . Stripe::VERSION,
'Authorization: Bearer ' . $myApiKey);
if (Stripe::$apiVersion)
$headers[] = 'Stripe-Version: ' . Stripe::$apiVersion;
list($rbody, $rcode) = $this->_curlRequest($meth, $absUrl, $headers, $params);
return array($rbody, $rcode, $myApiKey);
}
private function _interpretResponse($rbody, $rcode)
{
try {
$resp = json_decode($rbody, true);
} catch (Exception $e) {
throw new Stripe_ApiError("Invalid response body from API: $rbody (HTTP response code was $rcode)", $rcode, $rbody);
}
if ($rcode < 200 || $rcode >= 300) {
$this->handleApiError($rbody, $rcode, $resp);
}
return $resp;
}
private function _curlRequest($meth, $absUrl, $headers, $params)
{
$curl = curl_init();
$meth = strtolower($meth);
$opts = array();
if ($meth == 'get') {
$opts[CURLOPT_HTTPGET] = 1;
if (count($params) > 0) {
$encoded = self::encode($params);
$absUrl = "$absUrl?$encoded";
}
} else if ($meth == 'post') {
$opts[CURLOPT_POST] = 1;
$opts[CURLOPT_POSTFIELDS] = self::encode($params);
} else if ($meth == 'delete') {
$opts[CURLOPT_CUSTOMREQUEST] = 'DELETE';
if (count($params) > 0) {
$encoded = self::encode($params);
$absUrl = "$absUrl?$encoded";
}
} else {
throw new Stripe_ApiError("Unrecognized method $meth");
}
$absUrl = self::utf8($absUrl);
$opts[CURLOPT_URL] = $absUrl;
$opts[CURLOPT_RETURNTRANSFER] = true;
$opts[CURLOPT_CONNECTTIMEOUT] = 30;
$opts[CURLOPT_TIMEOUT] = 80;
$opts[CURLOPT_RETURNTRANSFER] = true;
$opts[CURLOPT_HTTPHEADER] = $headers;
if (!Stripe::$verifySslCerts)
$opts[CURLOPT_SSL_VERIFYPEER] = false;
curl_setopt_array($curl, $opts);
$rbody = curl_exec($curl);
$errno = curl_errno($curl);
if ($errno == CURLE_SSL_CACERT ||
$errno == CURLE_SSL_PEER_CERTIFICATE ||
$errno == 77 // CURLE_SSL_CACERT_BADFILE (constant not defined in PHP though)
) {
array_push($headers, 'X-Stripe-Client-Info: {"ca":"using Stripe-supplied CA bundle"}');
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
curl_setopt($curl, CURLOPT_CAINFO,
dirname(__FILE__) . '/../data/ca-certificates.crt');
$rbody = curl_exec($curl);
}
if ($rbody === false) {
$errno = curl_errno($curl);
$message = curl_error($curl);
curl_close($curl);
$this->handleCurlError($errno, $message);
}
$rcode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
curl_close($curl);
return array($rbody, $rcode);
}
public function handleCurlError($errno, $message)
{
$apiBase = Stripe::$apiBase;
switch ($errno) {
case CURLE_COULDNT_CONNECT:
case CURLE_COULDNT_RESOLVE_HOST:
case CURLE_OPERATION_TIMEOUTED:
$msg = "Could not connect to Stripe ($apiBase). Please check your internet connection and try again. If this problem persists, you should check Stripe's service status at https://twitter.com/stripestatus, or let us know at support@stripe.com.";
break;
case CURLE_SSL_CACERT:
case CURLE_SSL_PEER_CERTIFICATE:
$msg = "Could not verify Stripe's SSL certificate. Please make sure that your network is not intercepting certificates. (Try going to $apiBase in your browser.) If this problem persists, let us know at support@stripe.com.";
break;
default:
$msg = "Unexpected error communicating with Stripe. If this problem persists, let us know at support@stripe.com.";
}
$msg .= "\n\n(Network error [errno $errno]: $message)";
throw new Stripe_ApiConnectionError($msg);
}
}

View File

@ -1,104 +0,0 @@
<?php
abstract class Stripe_ApiResource extends Stripe_Object
{
protected static function _scopedRetrieve($class, $id, $apiKey=null)
{
$instance = new $class($id, $apiKey);
$instance->refresh();
return $instance;
}
public function refresh()
{
$requestor = new Stripe_ApiRequestor($this->_apiKey);
$url = $this->instanceUrl();
list($response, $apiKey) = $requestor->request('get', $url, $this->_retrieveOptions);
$this->refreshFrom($response, $apiKey);
return $this;
}
public static function className($class)
{
// Useful for namespaces: Foo\Stripe_Charge
if ($postfix = strrchr($class, '\\'))
$class = substr($postfix, 1);
if (substr($class, 0, strlen('Stripe')) == 'Stripe')
$class = substr($class, strlen('Stripe'));
$class = str_replace('_', '', $class);
$name = urlencode($class);
$name = strtolower($name);
return $name;
}
public static function classUrl($class)
{
$base = self::className($class);
return "/v1/${base}s";
}
public function instanceUrl()
{
$id = $this['id'];
$class = get_class($this);
if (!$id) {
throw new Stripe_InvalidRequestError("Could not determine which URL to request: $class instance has invalid ID: $id", null);
}
$id = Stripe_ApiRequestor::utf8($id);
$base = self::classUrl($class);
$extn = urlencode($id);
return "$base/$extn";
}
private static function _validateCall($method, $params=null, $apiKey=null)
{
if ($params && !is_array($params))
throw new Stripe_Error("You must pass an array as the first argument to Stripe API method calls. (HINT: an example call to create a charge would be: \"StripeCharge::create(array('amount' => 100, 'currency' => 'usd', 'card' => array('number' => 4242424242424242, 'exp_month' => 5, 'exp_year' => 2015)))\")");
if ($apiKey && !is_string($apiKey))
throw new Stripe_Error('The second argument to Stripe API method calls is an optional per-request apiKey, which must be a string. (HINT: you can set a global apiKey by "Stripe::setApiKey(<apiKey>)")');
}
protected static function _scopedAll($class, $params=null, $apiKey=null)
{
self::_validateCall('all', $params, $apiKey);
$requestor = new Stripe_ApiRequestor($apiKey);
$url = self::classUrl($class);
list($response, $apiKey) = $requestor->request('get', $url, $params);
return Stripe_Util::convertToStripeObject($response, $apiKey);
}
protected static function _scopedCreate($class, $params=null, $apiKey=null)
{
self::_validateCall('create', $params, $apiKey);
$requestor = new Stripe_ApiRequestor($apiKey);
$url = self::classUrl($class);
list($response, $apiKey) = $requestor->request('post', $url, $params);
return Stripe_Util::convertToStripeObject($response, $apiKey);
}
protected function _scopedSave($class)
{
self::_validateCall('save');
if ($this->_unsavedValues) {
$requestor = new Stripe_ApiRequestor($this->_apiKey);
$params = array();
foreach ($this->_unsavedValues->toArray() as $k)
$params[$k] = $this->$k;
$url = $this->instanceUrl();
list($response, $apiKey) = $requestor->request('post', $url, $params);
$this->refreshFrom($response, $apiKey);
}
return $this;
}
protected function _scopedDelete($class, $params=null)
{
self::_validateCall('delete');
$requestor = new Stripe_ApiRequestor($this->_apiKey);
$url = $this->instanceUrl();
list($response, $apiKey) = $requestor->request('delete', $url, $params);
$this->refreshFrom($response, $apiKey);
return $this;
}
}

View File

@ -1,5 +0,0 @@
<?php
class Stripe_AuthenticationError extends Stripe_Error
{
}

View File

@ -1,11 +0,0 @@
<?php
class Stripe_CardError extends Stripe_Error
{
public function __construct($message, $param, $code, $http_status=null, $http_body=null, $json_body=null)
{
parent::__construct($message, $http_status, $http_body, $json_body);
$this->param = $param;
$this->code = $code;
}
}

View File

@ -1,61 +0,0 @@
<?php
class Stripe_Charge extends Stripe_ApiResource
{
public static function constructFrom($values, $apiKey=null)
{
$class = get_class();
return self::scopedConstructFrom($class, $values, $apiKey);
}
public static function retrieve($id, $apiKey=null)
{
$class = get_class();
return self::_scopedRetrieve($class, $id, $apiKey);
}
public static function all($params=null, $apiKey=null)
{
$class = get_class();
return self::_scopedAll($class, $params, $apiKey);
}
public static function create($params=null, $apiKey=null)
{
$class = get_class();
return self::_scopedCreate($class, $params, $apiKey);
}
public function save()
{
$class = get_class();
return self::_scopedSave($class);
}
public function refund($params=null)
{
$requestor = new Stripe_ApiRequestor($this->_apiKey);
$url = $this->instanceUrl() . '/refund';
list($response, $apiKey) = $requestor->request('post', $url, $params);
$this->refreshFrom($response, $apiKey);
return $this;
}
public function capture($params=null)
{
$requestor = new Stripe_ApiRequestor($this->_apiKey);
$url = $this->instanceUrl() . '/capture';
list($response, $apiKey) = $requestor->request('post', $url, $params);
$this->refreshFrom($response, $apiKey);
return $this;
}
public function updateDispute($params=null)
{
$requestor = new Stripe_ApiRequestor($this->_apiKey);
$url = $this->instanceUrl() . '/dispute';
list($response, $apiKey) = $requestor->request('post', $url, $params);
$this->refreshFrom(array('dispute' => $response), $apiKey, true);
return $this->dispute;
}
}

View File

@ -1,34 +0,0 @@
<?php
class Stripe_Coupon extends Stripe_ApiResource
{
public static function constructFrom($values, $apiKey=null)
{
$class = get_class();
return self::scopedConstructFrom($class, $values, $apiKey);
}
public static function retrieve($id, $apiKey=null)
{
$class = get_class();
return self::_scopedRetrieve($class, $id, $apiKey);
}
public static function create($params=null, $apiKey=null)
{
$class = get_class();
return self::_scopedCreate($class, $params, $apiKey);
}
public function delete($params=null)
{
$class = get_class();
return self::_scopedDelete($class, $params);
}
public static function all($params=null, $apiKey=null)
{
$class = get_class();
return self::_scopedAll($class, $params, $apiKey);
}
}

View File

@ -1,102 +0,0 @@
<?php
class Stripe_Customer extends Stripe_ApiResource
{
public static function constructFrom($values, $apiKey=null)
{
$class = get_class();
return self::scopedConstructFrom($class, $values, $apiKey);
}
public static function retrieve($id, $apiKey=null)
{
$class = get_class();
return self::_scopedRetrieve($class, $id, $apiKey);
}
public static function all($params=null, $apiKey=null)
{
$class = get_class();
return self::_scopedAll($class, $params, $apiKey);
}
public static function create($params=null, $apiKey=null)
{
$class = get_class();
return self::_scopedCreate($class, $params, $apiKey);
}
public function save()
{
$class = get_class();
return self::_scopedSave($class);
}
public function delete($params=null)
{
$class = get_class();
return self::_scopedDelete($class, $params);
}
public function addInvoiceItem($params=null)
{
if (!$params)
$params = array();
$params['customer'] = $this->id;
$ii = Stripe_InvoiceItem::create($params, $this->_apiKey);
return $ii;
}
public function invoices($params=null)
{
if (!$params)
$params = array();
$params['customer'] = $this->id;
$invoices = Stripe_Invoice::all($params, $this->_apiKey);
return $invoices;
}
public function invoiceItems($params=null)
{
if (!$params)
$params = array();
$params['customer'] = $this->id;
$iis = Stripe_InvoiceItem::all($params, $this->_apiKey);
return $iis;
}
public function charges($params=null)
{
if (!$params)
$params = array();
$params['customer'] = $this->id;
$charges = Stripe_Charge::all($params, $this->_apiKey);
return $charges;
}
public function updateSubscription($params=null)
{
$requestor = new Stripe_ApiRequestor($this->_apiKey);
$url = $this->instanceUrl() . '/subscription';
list($response, $apiKey) = $requestor->request('post', $url, $params);
$this->refreshFrom(array('subscription' => $response), $apiKey, true);
return $this->subscription;
}
public function cancelSubscription($params=null)
{
$requestor = new Stripe_ApiRequestor($this->_apiKey);
$url = $this->instanceUrl() . '/subscription';
list($response, $apiKey) = $requestor->request('delete', $url, $params);
$this->refreshFrom(array('subscription' => $response), $apiKey, true);
return $this->subscription;
}
public function deleteDiscount()
{
$requestor = new Stripe_ApiRequestor($this->_apiKey);
$url = $this->instanceUrl() . '/discount';
list($response, $apiKey) = $requestor->request('delete', $url);
$this->refreshFrom(array('discount' => null), $apiKey, true);
}
}

View File

@ -1,27 +0,0 @@
<?php
class Stripe_Error extends Exception
{
public function __construct($message=null, $http_status=null, $http_body=null, $json_body=null)
{
parent::__construct($message);
$this->http_status = $http_status;
$this->http_body = $http_body;
$this->json_body = $json_body;
}
public function getHttpStatus()
{
return $this->http_status;
}
public function getHttpBody()
{
return $this->http_body;
}
public function getJsonBody()
{
return $this->json_body;
}
}

View File

@ -1,22 +0,0 @@
<?php
class Stripe_Event extends Stripe_ApiResource
{
public static function constructFrom($values, $apiKey=null)
{
$class = get_class();
return self::scopedConstructFrom($class, $values, $apiKey);
}
public static function retrieve($id, $apiKey=null)
{
$class = get_class();
return self::_scopedRetrieve($class, $id, $apiKey);
}
public static function all($params=null, $apiKey=null)
{
$class = get_class();
return self::_scopedAll($class, $params, $apiKey);
}
}

View File

@ -1,10 +0,0 @@
<?php
class Stripe_InvalidRequestError extends Stripe_Error
{
public function __construct($message, $param, $http_status=null, $http_body=null, $json_body=null)
{
parent::__construct($message, $http_status, $http_body, $json_body);
$this->param = $param;
}
}

View File

@ -1,51 +0,0 @@
<?php
class Stripe_Invoice extends Stripe_ApiResource
{
public static function constructFrom($values, $apiKey=null)
{
$class = get_class();
return self::scopedConstructFrom($class, $values, $apiKey);
}
public static function create($params=null, $apiKey=null)
{
$class = get_class();
return self::_scopedCreate($class, $params, $apiKey);
}
public static function retrieve($id, $apiKey=null)
{
$class = get_class();
return self::_scopedRetrieve($class, $id, $apiKey);
}
public static function all($params=null, $apiKey=null)
{
$class = get_class();
return self::_scopedAll($class, $params, $apiKey);
}
public static function upcoming($params=null, $apiKey=null)
{
$requestor = new Stripe_ApiRequestor($apiKey);
$url = self::classUrl(get_class()) . '/upcoming';
list($response, $apiKey) = $requestor->request('get', $url, $params);
return Stripe_Util::convertToStripeObject($response, $apiKey);
}
public function save()
{
$class = get_class();
return self::_scopedSave($class);
}
public function pay()
{
$requestor = new Stripe_ApiRequestor($this->_apiKey);
$url = $this->instanceUrl() . '/pay';
list($response, $apiKey) = $requestor->request('post', $url);
$this->refreshFrom($response, $apiKey);
return $this;
}
}

View File

@ -1,40 +0,0 @@
<?php
class Stripe_InvoiceItem extends Stripe_ApiResource
{
public static function constructFrom($values, $apiKey=null)
{
$class = get_class();
return self::scopedConstructFrom($class, $values, $apiKey);
}
public static function retrieve($id, $apiKey=null)
{
$class = get_class();
return self::_scopedRetrieve($class, $id, $apiKey);
}
public static function all($params=null, $apiKey=null)
{
$class = get_class();
return self::_scopedAll($class, $params, $apiKey);
}
public static function create($params=null, $apiKey=null)
{
$class = get_class();
return self::_scopedCreate($class, $params, $apiKey);
}
public function save()
{
$class = get_class();
return self::_scopedSave($class);
}
public function delete($params=null)
{
$class = get_class();
return self::_scopedDelete($class, $params);
}
}

View File

@ -1,17 +0,0 @@
<?php
class Stripe_List extends Stripe_Object
{
public static function constructFrom($values, $apiKey=null)
{
$class = get_class();
return self::scopedConstructFrom($class, $values, $apiKey);
}
public function all($params=null)
{
$requestor = new Stripe_ApiRequestor($this->_apiKey);
list($response, $apiKey) = $requestor->request('get', $this['url'], $params);
return Stripe_Util::convertToStripeObject($response, $apiKey);
}
}

View File

@ -1,155 +0,0 @@
<?php
class Stripe_Object implements ArrayAccess
{
public static $_permanentAttributes;
public static function init()
{
self::$_permanentAttributes = new Stripe_Util_Set(array('_apiKey', 'id'));
}
protected $_apiKey;
protected $_values;
protected $_unsavedValues;
protected $_transientValues;
protected $_retrieveOptions;
public function __construct($id=null, $apiKey=null)
{
$this->_apiKey = $apiKey;
$this->_values = array();
$this->_unsavedValues = new Stripe_Util_Set();
$this->_transientValues = new Stripe_Util_Set();
$this->_retrieveOptions = array();
if (is_array($id)) {
foreach($id as $key => $value) {
if ($key != 'id')
$this->_retrieveOptions[$key] = $value;
}
$id = $id['id'];
}
if ($id)
$this->id = $id;
}
// Standard accessor magic methods
public function __set($k, $v)
{
// TODO: may want to clear from $_transientValues. (Won't be user-visible.)
$this->_values[$k] = $v;
if (!self::$_permanentAttributes->includes($k))
$this->_unsavedValues->add($k);
}
public function __isset($k)
{
return isset($this->_values[$k]);
}
public function __unset($k)
{
unset($this->_values[$k]);
$this->_transientValues->add($k);
$this->_unsavedValues->discard($k);
}
public function __get($k)
{
if (array_key_exists($k, $this->_values)) {
return $this->_values[$k];
} else if ($this->_transientValues->includes($k)) {
$class = get_class($this);
$attrs = join(', ', array_keys($this->_values));
error_log("Stripe Notice: Undefined property of $class instance: $k. HINT: The $k attribute was set in the past, however. It was then wiped when refreshing the object with the result returned by Stripe's API, probably as a result of a save(). The attributes currently available on this object are: $attrs");
return null;
} else {
$class = get_class($this);
error_log("Stripe Notice: Undefined property of $class instance: $k");
return null;
}
}
// ArrayAccess methods
public function offsetSet($k, $v)
{
$this->$k = $v;
}
public function offsetExists($k)
{
return array_key_exists($k, $this->_values);
}
public function offsetUnset($k)
{
unset($this->$k);
}
public function offsetGet($k)
{
return array_key_exists($k, $this->_values) ? $this->_values[$k] : null;
}
// This unfortunately needs to be public to be used in Util.php
public static function scopedConstructFrom($class, $values, $apiKey=null)
{
$obj = new $class(isset($values['id']) ? $values['id'] : null, $apiKey);
$obj->refreshFrom($values, $apiKey);
return $obj;
}
public static function constructFrom($values, $apiKey=null)
{
$class = get_class();
return self::scopedConstructFrom($class, $values, $apiKey);
}
public function refreshFrom($values, $apiKey, $partial=false)
{
$this->_apiKey = $apiKey;
// Wipe old state before setting new. This is useful for e.g. updating a
// customer, where there is no persistent card parameter. Mark those values
// which don't persist as transient
if ($partial)
$removed = new Stripe_Util_Set();
else
$removed = array_diff(array_keys($this->_values), array_keys($values));
foreach ($removed as $k) {
if (self::$_permanentAttributes->includes($k))
continue;
unset($this->$k);
}
foreach ($values as $k => $v) {
if (self::$_permanentAttributes->includes($k))
continue;
$this->_values[$k] = Stripe_Util::convertToStripeObject($v, $apiKey);
$this->_transientValues->discard($k);
$this->_unsavedValues->discard($k);
}
}
public function __toJSON()
{
if (defined('JSON_PRETTY_PRINT'))
return json_encode($this->__toArray(true), JSON_PRETTY_PRINT);
else
return json_encode($this->__toArray(true));
}
public function __toString()
{
return $this->__toJSON();
}
public function __toArray($recursive=false)
{
if ($recursive)
return Stripe_Util::convertStripeObjectToArray($this->_values);
else
return $this->_values;
}
}
Stripe_Object::init();

View File

@ -1,40 +0,0 @@
<?php
class Stripe_Plan extends Stripe_ApiResource
{
public static function constructFrom($values, $apiKey=null)
{
$class = get_class();
return self::scopedConstructFrom($class, $values, $apiKey);
}
public static function retrieve($id, $apiKey=null)
{
$class = get_class();
return self::_scopedRetrieve($class, $id, $apiKey);
}
public static function create($params=null, $apiKey=null)
{
$class = get_class();
return self::_scopedCreate($class, $params, $apiKey);
}
public function delete($params=null)
{
$class = get_class();
return self::_scopedDelete($class, $params);
}
public function save()
{
$class = get_class();
return self::_scopedSave($class);
}
public static function all($params=null, $apiKey=null)
{
$class = get_class();
return self::_scopedAll($class, $params, $apiKey);
}
}

View File

@ -1,50 +0,0 @@
<?php
class Stripe_Recipient extends Stripe_ApiResource
{
public static function constructFrom($values, $apiKey=null)
{
$class = get_class();
return self::scopedConstructFrom($class, $values, $apiKey);
}
public static function retrieve($id, $apiKey=null)
{
$class = get_class();
return self::_scopedRetrieve($class, $id, $apiKey);
}
public static function all($params=null, $apiKey=null)
{
$class = get_class();
return self::_scopedAll($class, $params, $apiKey);
}
public static function create($params=null, $apiKey=null)
{
$class = get_class();
return self::_scopedCreate($class, $params, $apiKey);
}
public function save()
{
$class = get_class();
return self::_scopedSave($class);
}
public function delete($params=null)
{
$class = get_class();
return self::_scopedDelete($class, $params);
}
public function transfers($params=null)
{
if (!$params)
$params = array();
$params['recipient'] = $this->id;
$transfers = Stripe_Transfer::all($params, $this->_apiKey);
return $transfers;
}
}

View File

@ -1,24 +0,0 @@
<?php
abstract class Stripe_SingletonApiResource extends Stripe_ApiResource
{
protected static function _scopedSingletonRetrieve($class, $apiKey=null)
{
$instance = new $class(null, $apiKey);
$instance->refresh();
return $instance;
}
public static function classUrl($class)
{
$base = self::className($class);
return "/v1/${base}";
}
public function instanceUrl()
{
$class = get_class($this);
$base = self::classUrl($class);
return "$base";
}
}

View File

@ -1,38 +0,0 @@
<?php
abstract class Stripe
{
public static $apiKey;
public static $apiBase = 'https://api.stripe.com';
public static $apiVersion = null;
public static $verifySslCerts = true;
const VERSION = '1.8.0';
public static function getApiKey()
{
return self::$apiKey;
}
public static function setApiKey($apiKey)
{
self::$apiKey = $apiKey;
}
public static function getApiVersion()
{
return self::$apiVersion;
}
public static function setApiVersion($apiVersion)
{
self::$apiVersion = $apiVersion;
}
public static function getVerifySslCerts() {
return self::$verifySslCerts;
}
public static function setVerifySslCerts($verify) {
self::$verifySslCerts = $verify;
}
}

View File

@ -1,22 +0,0 @@
<?php
class Stripe_Token extends Stripe_ApiResource
{
public static function constructFrom($values, $apiKey=null)
{
$class = get_class();
return self::scopedConstructFrom($class, $values, $apiKey);
}
public static function retrieve($id, $apiKey=null)
{
$class = get_class();
return self::_scopedRetrieve($class, $id, $apiKey);
}
public static function create($params=null, $apiKey=null)
{
$class = get_class();
return self::_scopedCreate($class, $params, $apiKey);
}
}

View File

@ -1,30 +0,0 @@
<?php
class Stripe_Transfer extends Stripe_ApiResource
{
public static function constructFrom($values, $apiKey=null)
{
$class = get_class();
return self::scopedConstructFrom($class, $values, $apiKey);
}
public static function retrieve($id, $apiKey=null)
{
$class = get_class();
return self::_scopedRetrieve($class, $id, $apiKey);
}
public static function all($params=null, $apiKey=null)
{
$class = get_class();
return self::_scopedAll($class, $params, $apiKey);
}
public static function create($params=null, $apiKey=null)
{
$class = get_class();
return self::_scopedCreate($class, $params, $apiKey);
}
}

View File

@ -1,66 +0,0 @@
<?php
abstract class Stripe_Util
{
public static function isList($array)
{
if (!is_array($array))
return false;
// TODO: this isn't actually correct in general, but it's correct given Stripe's responses
foreach (array_keys($array) as $k) {
if (!is_numeric($k))
return false;
}
return true;
}
public static function convertStripeObjectToArray($values)
{
$results = array();
foreach ($values as $k => $v) {
// FIXME: this is an encapsulation violation
if (Stripe_Object::$_permanentAttributes->includes($k)) {
continue;
}
if ($v instanceof Stripe_Object) {
$results[$k] = $v->__toArray(true);
}
else if (is_array($v)) {
$results[$k] = self::convertStripeObjectToArray($v);
}
else {
$results[$k] = $v;
}
}
return $results;
}
public static function convertToStripeObject($resp, $apiKey)
{
$types = array(
'charge' => 'Stripe_Charge',
'customer' => 'Stripe_Customer',
'list' => 'Stripe_List',
'invoice' => 'Stripe_Invoice',
'invoiceitem' => 'Stripe_InvoiceItem',
'event' => 'Stripe_Event',
'transfer' => 'Stripe_Transfer',
'plan' => 'Stripe_Plan',
'recipient' => 'Stripe_Recipient'
);
if (self::isList($resp)) {
$mapped = array();
foreach ($resp as $i)
array_push($mapped, self::convertToStripeObject($i, $apiKey));
return $mapped;
} else if (is_array($resp)) {
if (isset($resp['object']) && is_string($resp['object']) && isset($types[$resp['object']]))
$class = $types[$resp['object']];
else
$class = 'Stripe_Object';
return Stripe_Object::scopedConstructFrom($class, $resp, $apiKey);
} else {
return $resp;
}
}
}

View File

@ -1,34 +0,0 @@
<?php
class Stripe_Util_Set
{
private $_elts;
public function __construct($members=array())
{
$this->_elts = array();
foreach ($members as $item)
$this->_elts[$item] = true;
}
public function includes($elt)
{
return isset($this->_elts[$elt]);
}
public function add($elt)
{
$this->_elts[$elt] = true;
}
public function discard($elt)
{
unset($this->_elts[$elt]);
}
// TODO: make Set support foreach
public function toArray()
{
return array_keys($this->_elts);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,53 +0,0 @@
<?php
echo "Running the Stripe PHP bindings test suite.\n".
"If you're trying to use the Stripe PHP bindings you'll probably want ".
"to require('lib/Stripe.php'); instead of this file\n";
function authorizeFromEnv()
{
$apiKey = getenv('STRIPE_API_KEY');
if (!$apiKey)
$apiKey = "tGN0bIwXnHdwOa85VABjPdSn8nWY7G7I";
Stripe::setApiKey($apiKey);
}
$ok = @include_once(dirname(__FILE__).'/simpletest/autorun.php');
if (!$ok) {
$ok = @include_once(dirname(__FILE__).'/../vendor/vierbergenlars/simpletest/autorun.php');
}
if (!$ok) {
echo "MISSING DEPENDENCY: The Stripe API test cases depend on SimpleTest. ".
"Download it at <http://www.simpletest.org/>, and either install it ".
"in your PHP include_path or put it in the test/ directory.\n";
exit(1);
}
// Throw an exception on any error
function exception_error_handler($errno, $errstr, $errfile, $errline) {
throw new ErrorException($errstr, $errno, 0, $errfile, $errline);
}
set_error_handler('exception_error_handler');
error_reporting(E_ALL | E_STRICT);
require_once(dirname(__FILE__) . '/../lib/Stripe.php');
require_once(dirname(__FILE__) . '/Stripe/TestCase.php');
require_once(dirname(__FILE__) . '/Stripe/ApiRequestorTest.php');
require_once(dirname(__FILE__) . '/Stripe/AuthenticationErrorTest.php');
require_once(dirname(__FILE__) . '/Stripe/CardErrorTest.php');
require_once(dirname(__FILE__) . '/Stripe/AccountTest.php');
require_once(dirname(__FILE__) . '/Stripe/ChargeTest.php');
require_once(dirname(__FILE__) . '/Stripe/CouponTest.php');
require_once(dirname(__FILE__) . '/Stripe/CustomerTest.php');
require_once(dirname(__FILE__) . '/Stripe/DiscountTest.php');
require_once(dirname(__FILE__) . '/Stripe/Error.php');
require_once(dirname(__FILE__) . '/Stripe/InvalidRequestErrorTest.php');
require_once(dirname(__FILE__) . '/Stripe/InvoiceTest.php');
require_once(dirname(__FILE__) . '/Stripe/ObjectTest.php');
require_once(dirname(__FILE__) . '/Stripe/PlanTest.php');
require_once(dirname(__FILE__) . '/Stripe/Token.php');
require_once(dirname(__FILE__) . '/Stripe/TransferTest.php');
require_once(dirname(__FILE__) . '/Stripe/RecipientTest.php');
require_once(dirname(__FILE__) . '/Stripe/UtilTest.php');

View File

@ -1,13 +0,0 @@
<?php
class Stripe_AccountTest extends StripeTestCase
{
public function testRetrieve()
{
authorizeFromEnv();
$d = Stripe_Account::retrieve();
$this->assertEqual($d->email, "test+bindings@stripe.com");
$this->assertEqual($d->charge_enabled, false);
$this->assertEqual($d->details_submitted, false);
}
}

View File

@ -1,64 +0,0 @@
<?php
class Stripe_ApiRequestorTest extends UnitTestCase
{
public function testEncode()
{
$a = array('my' => 'value', 'that' => array('your' => 'example'), 'bar' => 1, 'baz' => null);
$enc = Stripe_APIRequestor::encode($a);
$this->assertEqual($enc, 'my=value&that%5Byour%5D=example&bar=1');
$a = array('that' => array('your' => 'example', 'foo' => null));
$enc = Stripe_APIRequestor::encode($a);
$this->assertEqual($enc, 'that%5Byour%5D=example');
$a = array('that' => 'example', 'foo' => array('bar', 'baz'));
$enc = Stripe_APIRequestor::encode($a);
$this->assertEqual($enc, 'that=example&foo%5B%5D=bar&foo%5B%5D=baz');
$a = array('my' => 'value', 'that' => array('your' => array('cheese', 'whiz', null)), 'bar' => 1, 'baz' => null);
$enc = Stripe_APIRequestor::encode($a);
$this->assertEqual($enc, 'my=value&that%5Byour%5D%5B%5D=cheese&that%5Byour%5D%5B%5D=whiz&bar=1');
}
public function testUtf8()
{
// UTF-8 string
$x = "\xc3\xa9";
$this->assertEqual(Stripe_ApiRequestor::utf8($x), $x);
// Latin-1 string
$x = "\xe9";
$this->assertEqual(Stripe_ApiRequestor::utf8($x), "\xc3\xa9");
// Not a string
$x = TRUE;
$this->assertEqual(Stripe_ApiRequestor::utf8($x), $x);
}
public function testEncodeObjects()
{
// We have to do some work here because this is normally
// private. This is just for testing! Also it only works on PHP >=
// 5.3
if (version_compare(PHP_VERSION, '5.3.2', '>=')) {
$reflector = new ReflectionClass('Stripe_APIRequestor');
$method = $reflector->getMethod('_encodeObjects');
$method->setAccessible(true);
$a = array('customer' => new Stripe_Customer('abcd'));
$enc = $method->invoke(null, $a);
$this->assertEqual($enc, array('customer' => 'abcd'));
// Preserves UTF-8
$v = array('customer' => "");
$enc = $method->invoke(null, $v);
$this->assertEqual($enc, $v);
// Encodes latin-1 -> UTF-8
$v = array('customer' => "\xe9");
$enc = $method->invoke(null, $v);
$this->assertEqual($enc, array('customer' => "\xc3\xa9"));
}
}
}

View File

@ -1,14 +0,0 @@
<?php
class Stripe_AuthenticationErrorTest extends UnitTestCase
{
public function testInvalidCredentials()
{
Stripe::setApiKey('invalid');
try {
Stripe_Customer::create();
} catch (Stripe_AuthenticationError $e) {
$this->assertEqual(401, $e->getHttpStatus());
}
}
}

View File

@ -1,16 +0,0 @@
<?php
class Stripe_CardErrorTest extends UnitTestCase
{
public function testDecline()
{
authorizeFromEnv();
try {
Stripe_Charge::create(array('amount' => 100, 'currency' => 'usd', 'card' => array('number' => '4000000000000002', 'exp_month' => '3', 'exp_year' => '2020')));
} catch (Stripe_CardError $e) {
$this->assertEqual(402, $e->getHttpStatus());
$body = $e->getJsonBody();
$this->assertTrue($body['error']);
}
}
}

View File

@ -1,35 +0,0 @@
<?php
class Stripe_ChargeTest extends UnitTestCase
{
public function testUrls()
{
$this->assertEqual(Stripe_Charge::classUrl('Stripe_Charge'), '/v1/charges');
$charge = new Stripe_Charge('abcd/efgh');
$this->assertEqual($charge->instanceUrl(), '/v1/charges/abcd%2Fefgh');
}
public function testCreate()
{
authorizeFromEnv();
$c = Stripe_Charge::create(array('amount' => 100,
'currency' => 'usd',
'card' => array('number' => '4242424242424242',
'exp_month' => 5,
'exp_year' => 2015)));
$this->assertTrue($c->paid);
$this->assertFalse($c->refunded);
}
public function testRetrieve()
{
authorizeFromEnv();
$c = Stripe_Charge::create(array('amount' => 100,
'currency' => 'usd',
'card' => array('number' => '4242424242424242',
'exp_month' => 5,
'exp_year' => 2015)));
$d = Stripe_Charge::retrieve($c->id);
$this->assertEqual($d->id, $c->id);
}
}

View File

@ -1,17 +0,0 @@
<?php
class Stripe_CouponTest extends StripeTestCase
{
public function testCreate()
{
authorizeFromEnv();
$id = 'test_coupon-' . self::randomString();
$c = Stripe_Coupon::create(array('percent_off' => 25,
'duration' => 'repeating',
'duration_in_months' => 5,
'id' => $id));
$this->assertEqual($id, $c->id);
$this->assertEqual(25, $c->percent_off);
}
}

View File

@ -1,58 +0,0 @@
<?php
class Stripe_CustomerTest extends StripeTestCase
{
public function testDeletion()
{
$customer = self::createTestCustomer();
$customer->delete();
$this->assertTrue($customer->deleted);
$this->assertNull($customer['active_card']);
}
public function testSave()
{
$customer = self::createTestCustomer();
$customer->email = 'gdb@stripe.com';
$customer->save();
$this->assertEqual($customer->email, 'gdb@stripe.com');
$customer2 = Stripe_Customer::retrieve($customer->id);
$this->assertEqual($customer->email, $customer2->email);
}
public function testBogusAttribute()
{
$customer = self::createTestCustomer();
$customer->bogus = 'bogus';
$caught = null;
try {
$customer->save();
} catch (Stripe_InvalidRequestError $exception) {
$caught = $exception;
}
$this->assertTrue($caught instanceof Stripe_InvalidRequestError);
}
public function testCancelSubscription()
{
$plan_id = 'gold-' . self::randomString();
self::retrieveOrCreatePlan($plan_id);
$customer = self::createTestCustomer(
array(
'plan' => $plan_id,
));
$customer->cancelSubscription(array('at_period_end' => true));
$this->assertEqual($customer->subscription->status, 'active');
$this->assertTrue($customer->subscription->cancel_at_period_end);
$customer->cancelSubscription();
$this->assertEqual($customer->subscription->status, 'canceled');
}
}

View File

@ -1,25 +0,0 @@
<?php
class Stripe_DiscountTest extends StripeTestCase
{
public function testDeletion()
{
authorizeFromEnv();
$id = 'test-coupon-' . self::randomString();
$coupon = Stripe_Coupon::create(array('percent_off' => 25,
'duration' => 'repeating',
'duration_in_months' => 5,
'id' => $id));
$customer = self::createTestCustomer(array('coupon' => $id));
$this->assertTrue(isset($customer->discount));
$this->assertTrue(isset($customer->discount->coupon));
$this->assertEqual($id, $customer->discount->coupon->id);
$customer->deleteDiscount();
$this->assertFalse(isset($customer->discount));
$customer = Stripe_Customer::retrieve($customer->id);
$this->assertFalse(isset($customer->discount));
}
}

View File

@ -1,17 +0,0 @@
<?php
class Stripe_ErrorTest extends UnitTestCase
{
public function testCreation()
{
try {
throw new Stripe_Error("hello", 500, "{'foo':'bar'}", array('foo' => 'bar'));
$this->fail("Did not raise error");
} catch (Stripe_Error $e) {
$this->assertEqual("hello", $e->getMessage());
$this->assertEqual(500, $e->getHttpStatus());
$this->assertEqual("{'foo':'bar'}", $e->getHttpBody());
$this->assertEqual(array('foo' => 'bar'), $e->getJsonBody());
}
}
}

Some files were not shown because too many files have changed in this diff Show More