Compare commits

...

2 Commits

Author SHA1 Message Date
c4b9540b2c Edit create-payment-intent.php via Editor 2025-10-19 21:20:02 +00:00
Flatlogic Bot
f03532c201 12 2025-10-19 20:05:43 +00:00
106 changed files with 11853 additions and 140 deletions

34
assets/css/custom.css Normal file
View File

@ -0,0 +1,34 @@
body {
background-color: #ECE5DD;
font-family: 'Helvetica', 'Arial', sans-serif;
}
.card {
border-radius: 0.75rem;
border: none;
}
.btn-primary {
background-color: #25D366;
border-color: #25D366;
background-image: linear-gradient(to right, #25D366, #128C7E);
}
.btn-primary:hover {
background-color: #128C7E;
border-color: #128C7E;
background-image: none;
}
.form-control:focus {
border-color: #25D366;
box-shadow: 0 0 0 0.25rem rgba(37, 211, 102, 0.25);
}
#status.online {
color: #25D366;
}
#status.offline {
color: #dc3545;
}

63
assets/js/main.js Normal file
View File

@ -0,0 +1,63 @@
document.addEventListener('DOMContentLoaded', function () {
const checkStatusForm = document.getElementById('checkStatusForm');
const submitButton = document.getElementById('submitButton');
const loadingDiv = document.getElementById('loading');
const resultDiv = document.getElementById('result');
const statusText = document.getElementById('statusText');
const lastSeen = document.getElementById('lastSeen');
if (checkStatusForm) {
checkStatusForm.addEventListener('submit', function (e) {
e.preventDefault();
// Hide previous result and show loading
resultDiv.style.display = 'none';
loadingDiv.style.display = 'block';
submitButton.disabled = true;
submitButton.innerHTML = '<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span> Buscando...';
const isPremium = checkStatusForm.dataset.premium === 'true';
// Simulate a 3-second delay
setTimeout(() => {
let status = '';
let lastSeenText = '';
let statusColor = '';
if (isPremium) {
// Premium user experience
status = 'En Línea';
lastSeenText = 'escribiendo...';
statusColor = '#25D366'; // WhatsApp Green
} else {
// Standard user experience
const isOnline = Math.random() < 0.5;
status = isOnline ? 'En Línea' : 'Desconectado';
statusColor = isOnline ? '#25D366' : '#dc3545'; // Red for offline
if (isOnline) {
lastSeenText = 'últ. vez hoy a las ' + new Date().toLocaleTimeString('es-ES', { hour: '2-digit', minute: '2-digit' });
} else {
const hoursAgo = Math.floor(Math.random() * 23) + 1;
const minutesAgo = Math.floor(Math.random() * 59);
lastSeenText = `últ. vez hace ${hoursAgo}h ${minutesAgo}m`;
}
}
// Update status text and color
statusText.innerText = status;
statusText.style.color = statusColor;
lastSeen.innerText = lastSeenText;
// Hide loading and show result
loadingDiv.style.display = 'none';
resultDiv.style.display = 'block';
// Re-enable button
submitButton.disabled = false;
submitButton.innerHTML = 'Ver Estado';
}, 3000);
});
}
});

42
assets/js/payment.js Normal file
View File

@ -0,0 +1,42 @@
document.addEventListener('DOMContentLoaded', async () => {
const stripe = Stripe('pk_live_51SJvpVAgq1ywLQy0IPutpWNtY9AmGKijmeu0MgxOxsNQEXW1nsdrLuUS0o7aU2Cnki6OwkZ1YhV10nCVcBgRuWjO00jh0pFCLY');
const { clientSecret } = await fetch('create-payment-intent.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({})
}).then(r => r.json());
const elements = stripe.elements({ clientSecret });
const cardElement = elements.create('card');
cardElement.mount('#card-element');
const form = document.getElementById('payment-form');
const errorContainer = document.getElementById('card-errors');
form.addEventListener('submit', async (event) => {
event.preventDefault();
const { error } = await stripe.confirmPayment({
elements,
confirmParams: {
return_url: window.location.href.split('?')[0] + '?payment=success'
}
});
if (error) {
errorContainer.textContent = error.message;
} else {
errorContainer.textContent = '';
}
});
const urlParams = new URLSearchParams(window.location.search);
if (urlParams.get('payment') === 'success') {
document.getElementById('card-payment-form').classList.add('d-none');
document.getElementById('spei-info').classList.add('d-none');
document.getElementById('payment-success').classList.remove('d-none');
}
});

5
composer.json Normal file
View File

@ -0,0 +1,5 @@
{
"require": {
"stripe/stripe-php": "^1.8"
}
}

71
composer.lock generated Normal file
View File

@ -0,0 +1,71 @@
{
"_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": "7ddc6309b099a518705cc62a6091e848",
"packages": [
{
"name": "stripe/stripe-php",
"version": "v1.18.0",
"source": {
"type": "git",
"url": "https://github.com/stripe/stripe-php.git",
"reference": "022c3f21ec1e4141b46738bd5e7ab730d04f78cc"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/stripe/stripe-php/zipball/022c3f21ec1e4141b46738bd5e7ab730d04f78cc",
"reference": "022c3f21ec1e4141b46738bd5e7ab730d04f78cc",
"shasum": ""
},
"require": {
"ext-curl": "*",
"ext-json": "*",
"ext-mbstring": "*",
"php": ">=5.2"
},
"require-dev": {
"simpletest/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/v1.18.0"
},
"time": "2015-01-22T05:01:46+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"
}

BIN
composer.phar Executable file

Binary file not shown.

46
create-payment-intent.php Normal file
View File

@ -0,0 +1,46 @@
<?php
require_once 'vendor/autoload.php';
require_once 'db/config.php';
session_start();
if (!isset($_SESSION['user_id'])) {
http_response_code(401);
echo json_encode(['error' => 'User not logged in']);
exit;
}
// It is not recommended to store the secret key directly in the code.
// It should be stored in an environment variable or a secure configuration file.
$stripeSecretKey = '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';
\Stripe\Stripe::setApiKey($stripeSecretKey);
header('Content-Type: application/json');
try {
$pdo = db();
$userId = $_SESSION['user_id'];
// Create a PaymentIntent with amount and currency
$paymentIntent = \Stripe\PaymentIntent::create([
'amount' => 18000, // 180.00 MXN
'currency' => 'mxn',
'metadata' => [
'user_id' => $userId
]
]);
// Save the payment intent to the database
$stmt = $pdo->prepare("INSERT INTO payments (user_id, stripe_payment_intent_id, amount, currency, status) VALUES (?, ?, ?, ?, ?)");
$stmt->execute([$userId, $paymentIntent->id, $paymentIntent->amount, $paymentIntent->currency, 'requires_payment_method']);
$output = [
'clientSecret' => $paymentIntent->client_secret,
];
echo json_encode($output);
} catch (Exception $e) {
http_response_code(500);
echo json_encode(['error' => $e->getMessage()]);
}

View File

@ -0,0 +1,17 @@
CREATE TABLE IF NOT EXISTS `users` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`email` VARCHAR(255) UNIQUE NOT NULL,
`is_premium` BOOLEAN NOT NULL DEFAULT FALSE,
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS `payments` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`user_id` INT,
`stripe_payment_intent_id` VARCHAR(255) UNIQUE NOT NULL,
`amount` INT NOT NULL,
`currency` VARCHAR(10) NOT NULL,
`status` VARCHAR(50) NOT NULL,
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id)
);

3
includes/footer.php Normal file
View File

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

45
includes/header.php Normal file
View File

@ -0,0 +1,45 @@
<?php session_start(); ?>
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Rastreador WhatsApp</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.10.5/font/bootstrap-icons.css">
<link rel="stylesheet" href="assets/css/custom.css">
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-dark" style="background-color: #128C7E;">
<div class="container">
<a class="navbar-brand" href="index.php">
<i class="bi bi-shield-check"></i> Rastreador WhatsApp
</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav ms-auto">
<?php if (isset($_SESSION['user_id'])): ?>
<li class="nav-item">
<a class="nav-link" href="#">Hola, <?php echo htmlspecialchars($_SESSION['user_email']); ?></a>
</li>
<li class="nav-item">
<a class="nav-link" href="premium.php">Premium</a>
</li>
<li class="nav-item">
<a class="nav-link" href="logout.php">Logout</a>
</li>
<?php else: ?>
<li class="nav-item">
<a class="nav-link" href="login.php">Login</a>
</li>
<li class="nav-item">
<a class="nav-link" href="register.php">Register</a>
</li>
<?php endif; ?>
</ul>
</div>
</div>
</nav>

215
index.php
View File

@ -1,150 +1,85 @@
<?php
declare(strict_types=1);
@ini_set('display_errors', '1');
@error_reporting(E_ALL);
@date_default_timezone_set('UTC');
session_start();
require_once 'db/config.php';
$phpVersion = PHP_VERSION;
$now = date('Y-m-d H:i:s');
$is_premium = false;
if (isset($_SESSION['user_id'])) {
$pdo = db();
$stmt = $pdo->prepare("SELECT is_premium FROM users WHERE id = ?");
$stmt->execute([$_SESSION['user_id']]);
$user = $stmt->fetch();
if ($user && $user['is_premium']) {
$is_premium = true;
}
}
?>
<!doctype html>
<!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>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WhatsApp Status Checker</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.10.5/font/bootstrap-icons.css">
<link rel="stylesheet" href="assets/css/custom.css">
</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>
<?php include 'includes/header.php'; ?>
<div class="container">
<div class="row justify-content-center">
<div class="col-md-6">
<div class="card shadow-lg border-0" style="border-radius: 0.75rem;">
<div class="card-body p-5">
<div class="text-center mb-4">
<i class="bi bi-whatsapp" style="font-size: 4rem; color: #25D366;"></i>
<h1 class="h3 mb-3 fw-normal">Verificador de Estado</h1>
<p class="text-muted">Ingresa un número de teléfono para verificar si está en línea.</p>
</div>
<form id="checkStatusForm" data-premium="<?php echo $is_premium ? 'true' : 'false'; ?>">
<div class="input-group mb-3">
<span class="input-group-text" style="border-radius: 0.75rem 0 0 0.75rem;"><i class="bi bi-telephone-fill"></i></span>
<input type="tel" class="form-control" id="phoneNumber" placeholder="Ej: +14155552671" required>
</div>
<div class="d-grid">
<button type="submit" class="btn btn-primary btn-lg gradient-background" id="submitButton">Ver Estado</button>
</div>
</form>
<div id="loading" class="text-center mt-4" style="display: none;">
<div class="spinner-border text-success" role="status">
<span class="visually-hidden">Loading...</span>
</div>
<p class="mt-2">Buscando...</p>
</div>
<div id="result" class="mt-4" style="display: none;">
<div class="card text-center">
<div class="card-body">
<h5 class="card-title">Resultado</h5>
<p class="card-text fs-4" id="statusText"></p>
<p class="card-text text-muted" id="lastSeen"></p>
</div>
</div>
</div>
</div>
</div>
<?php if (!isset($_SESSION['user_id'])):
?>
<div class="alert alert-info mt-4">
<a href="register.php">Regístrate</a> para una mejor experiencia y resultados más precisos.
</div>
<?php endif; ?>
</div>
</div>
</div>
</main>
<footer>
Page updated: <?= htmlspecialchars($now) ?> (UTC)
</footer>
<?php include 'includes/footer.php'; ?>
<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>

96
login.php Normal file
View File

@ -0,0 +1,96 @@
<?php
session_start();
require_once 'db/config.php';
$error = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$email = $_POST['email'] ?? '';
$password = $_POST['password'] ?? '';
if (empty($email) || empty($password)) {
$error = 'Please fill in all fields.';
} else {
$pdo = db();
$stmt = $pdo->prepare("SELECT * FROM users WHERE email = ?");
$stmt->execute([$email]);
$user = $stmt->fetch();
if ($user && password_verify($password, $user['password'])) {
$_SESSION['user_id'] = $user['id'];
$_SESSION['user_email'] = $user['email'];
header("Location: premium.php");
exit;
} else {
$error = 'Invalid email or password.';
}
}
}
?>
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Login - Rastreador WhatsApp</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.10.5/font/bootstrap-icons.css">
<link rel="stylesheet" href="assets/css/custom.css">
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-dark" style="background-color: #128C7E;">
<div class="container">
<a class="navbar-brand" href="index.php">
<i class="bi bi-shield-check"></i> Rastreador WhatsApp
</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<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 active" href="login.php">Login</a>
</li>
<li class="nav-item">
<a class="nav-link" href="register.php">Register</a>
</li>
</ul>
</div>
</div>
</nav>
<div class="container mt-5">
<div class="row justify-content-center">
<div class="col-md-6">
<div class="card shadow-lg" style="border-radius: 0.75rem;">
<div class="card-body p-5">
<h2 class="card-title text-center mb-4" style="color: #128C7E;">Login</h2>
<?php if ($error): ?>
<div class="alert alert-danger"><?php echo htmlspecialchars($error); ?></div>
<?php endif; ?>
<form action="login.php" method="POST">
<div class="mb-3">
<label for="email" class="form-label">Email Address</label>
<input type="email" class="form-control" id="email" name="email" required>
</div>
<div class="mb-3">
<label for="password" class="form-label">Password</label>
<input type="password" class="form-control" id="password" name="password" required>
</div>
<div class="d-grid">
<button type="submit" class="btn btn-primary btn-lg" style="background-color: #25D366; border-color: #25D366;">Login</button>
</div>
</form>
<p class="text-center mt-3">
Don't have an account? <a href="register.php" style="color: #128C7E;">Register here</a>.
</p>
</div>
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>

6
logout.php Normal file
View File

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

65
payment.php Normal file
View File

@ -0,0 +1,65 @@
<?php
require_once 'includes/header.php';
if (!isset($_SESSION['user_id'])) {
header("Location: login.php");
exit;
}
?>
<script src="https://js.stripe.com/v3/"></script>
<main class="container">
<div class="row justify-content-center">
<div class="col-md-6">
<div class="card text-center shadow-lg">
<div class="card-header">
<h2 class="fw-bold">Elige tu método de pago</h2>
</div>
<div class="card-body">
<p>Selecciona cómo te gustaría pagar para activar tu suscripción Premium.</p>
<div class="d-grid gap-2 my-4">
<button id="card-payment-btn" class="btn btn-primary btn-lg">Pagar con tarjeta</button>
<button id="spei-payment-btn" class="btn btn-secondary btn-lg">Pagar con SPEI</button>
</div>
<div id="card-payment-form" class="d-none">
<h5 class="fw-bold">Pago con Tarjeta</h5>
<form id="payment-form">
<div id="card-element" class="form-control mb-3">
<!-- A Stripe Element will be inserted here. -->
</div>
<button id="submit-button" class="btn btn-success w-100">Pagar $180.00 MXN</button>
<div id="card-errors" role="alert" class="text-danger mt-2"></div>
</form>
</div>
<div id="spei-info" class="alert alert-info mt-4 d-none">
<h5 class="fw-bold">Transferencia SPEI</h5>
<p>Realiza la transferencia a la siguiente CLABE:</p>
<p class="fw-bold fs-4">058597000079852715</p>
<p><small>Una vez realizado el pago, envía tu comprobante a <a href="mailto:applesaucetoaboss1413@gmail.com">applesaucetoaboss1413@gmail.com</a> para activar tu cuenta.</small></p>
</div>
<div id="payment-success" class="alert alert-success mt-4 d-none">
<h5 class="fw-bold">¡Premium activado!</h5>
<p>Gracias por tu pago. Ahora tienes acceso ilimitado.</p>
</div>
</div>
</div>
</div>
</div>
</main>
<script src="assets/js/payment.js"></script>
<script>
document.getElementById('spei-payment-btn').addEventListener('click', function() {
document.getElementById('spei-info').classList.remove('d-none');
document.getElementById('card-payment-form').classList.add('d-none');
});
document.getElementById('card-payment-btn').addEventListener('click', function() {
document.getElementById('card-payment-form').classList.remove('d-none');
document.getElementById('spei-info').classList.add('d-none');
});
</script>
<?php require_once 'includes/footer.php'; ?>

48
premium.php Normal file
View File

@ -0,0 +1,48 @@
<?php
require_once 'db/config.php';
require_once 'includes/header.php';
$is_premium = false;
if (isset($_SESSION['user_id'])) {
$pdo = db();
$stmt = $pdo->prepare("SELECT is_premium FROM users WHERE id = ?");
$stmt->execute([$_SESSION['user_id']]);
$user = $stmt->fetch();
if ($user && $user['is_premium']) {
$is_premium = true;
}
} else {
// If not logged in, redirect to login page
header("Location: login.php");
exit;
}
?>
<main class="container">
<div class="row justify-content-center">
<div class="col-md-6">
<div class="card text-center shadow-lg">
<div class="card-header">
<h2 class="fw-bold">Vuélvete Premium</h2>
</div>
<div class="card-body">
<?php if ($is_premium): ?>
<p class="card-text fs-4">¡Ya eres un usuario Premium!</p>
<p>Disfruta de todas las ventajas.</p>
<?php else: ?>
<p class="card-text">Disfruta de beneficios exclusivos con nuestro plan Premium.</p>
<ul class="list-unstyled my-4">
<li class="mb-2"><i class="bi bi-check-circle-fill text-success"></i> Consultas ilimitadas</li>
<li class="mb-2"><i class="bi bi-check-circle-fill text-success"></i> Sin anuncios</li>
<li class="mb-2"><i class="bi bi-check-circle-fill text-success"></i> Soporte prioritario</li>
</ul>
<h3 class="fw-bold mb-4">$180 MXN/mes</h3>
<a href="payment.php" class="btn btn-primary btn-lg w-100">Obtener Premium</a>
<?php endif; ?>
</div>
</div>
</div>
</div>
</main>
<?php require_once 'includes/footer.php'; ?>

105
register.php Normal file
View File

@ -0,0 +1,105 @@
<?php
session_start();
require_once 'db/config.php';
$error = '';
$success = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$email = $_POST['email'] ?? '';
$password = $_POST['password'] ?? '';
if (empty($email) || empty($password)) {
$error = 'Please fill in all fields.';
} elseif (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
$error = 'Invalid email format.';
} else {
$pdo = db();
$stmt = $pdo->prepare("SELECT * FROM users WHERE email = ?");
$stmt->execute([$email]);
$user = $stmt->fetch();
if ($user) {
$error = 'User with this email already exists.';
} else {
$hashed_password = password_hash($password, PASSWORD_DEFAULT);
$stmt = $pdo->prepare("INSERT INTO users (email, password) VALUES (?, ?)");
if ($stmt->execute([$email, $hashed_password])) {
$_SESSION['user_id'] = $pdo->lastInsertId();
$_SESSION['user_email'] = $email;
header("Location: premium.php");
exit;
} else {
$error = 'An error occurred. Please try again.';
}
}
}
}
?>
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Register - Rastreador WhatsApp</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.10.5/font/bootstrap-icons.css">
<link rel="stylesheet" href="assets/css/custom.css">
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-dark" style="background-color: #128C7E;">
<div class="container">
<a class="navbar-brand" href="index.php">
<i class="bi bi-shield-check"></i> Rastreador WhatsApp
</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<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="login.php">Login</a>
</li>
<li class="nav-item">
<a class="nav-link active" href="register.php">Register</a>
</li>
</ul>
</div>
</div>
</nav>
<div class="container mt-5">
<div class="row justify-content-center">
<div class="col-md-6">
<div class="card shadow-lg" style="border-radius: 0.75rem;">
<div class="card-body p-5">
<h2 class="card-title text-center mb-4" style="color: #128C7E;">Create Account</h2>
<?php if ($error): ?>
<div class="alert alert-danger"><?php echo htmlspecialchars($error); ?></div>
<?php endif; ?>
<form action="register.php" method="POST">
<div class="mb-3">
<label for="email" class="form-label">Email Address</label>
<input type="email" class="form-control" id="email" name="email" required>
</div>
<div class="mb-3">
<label for="password" class="form-label">Password</label>
<input type="password" class="form-control" id="password" name="password" required>
</div>
<div class="d-grid">
<button type="submit" class="btn btn-primary btn-lg" style="background-color: #25D366; border-color: #25D366;">Register</button>
</div>
</form>
<p class="text-center mt-3">
Already have an account? <a href="login.php" style="color: #128C7E;">Login here</a>.
</p>
</div>
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>

1
stripe-php.zip Normal file
View File

@ -0,0 +1 @@
Not Found

22
vendor/autoload.php vendored Normal file
View File

@ -0,0 +1,22 @@
<?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 ComposerAutoloaderInit40aa654f2e66c20881ae0572fe987a10::getLoader();

579
vendor/composer/ClassLoader.php vendored Normal file
View File

@ -0,0 +1,579 @@
<?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);
}
}

396
vendor/composer/InstalledVersions.php vendored Normal file
View File

@ -0,0 +1,396 @@
<?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;
}
}

21
vendor/composer/LICENSE vendored Normal file
View File

@ -0,0 +1,21 @@
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.

48
vendor/composer/autoload_classmap.php vendored Normal file
View File

@ -0,0 +1,48 @@
<?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_ApplicationFee' => $vendorDir . '/stripe/stripe-php/lib/Stripe/ApplicationFee.php',
'Stripe_ApplicationFeeRefund' => $vendorDir . '/stripe/stripe-php/lib/Stripe/ApplicationFeeRefund.php',
'Stripe_AttachedObject' => $vendorDir . '/stripe/stripe-php/lib/Stripe/AttachedObject.php',
'Stripe_AuthenticationError' => $vendorDir . '/stripe/stripe-php/lib/Stripe/AuthenticationError.php',
'Stripe_Balance' => $vendorDir . '/stripe/stripe-php/lib/Stripe/Balance.php',
'Stripe_BalanceTransaction' => $vendorDir . '/stripe/stripe-php/lib/Stripe/BalanceTransaction.php',
'Stripe_BitcoinReceiver' => $vendorDir . '/stripe/stripe-php/lib/Stripe/BitcoinReceiver.php',
'Stripe_BitcoinTransaction' => $vendorDir . '/stripe/stripe-php/lib/Stripe/BitcoinTransaction.php',
'Stripe_Card' => $vendorDir . '/stripe/stripe-php/lib/Stripe/Card.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_FileUpload' => $vendorDir . '/stripe/stripe-php/lib/Stripe/FileUpload.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_RateLimitError' => $vendorDir . '/stripe/stripe-php/lib/Stripe/RateLimitError.php',
'Stripe_Recipient' => $vendorDir . '/stripe/stripe-php/lib/Stripe/Recipient.php',
'Stripe_Refund' => $vendorDir . '/stripe/stripe-php/lib/Stripe/Refund.php',
'Stripe_RequestOptions' => $vendorDir . '/stripe/stripe-php/lib/Stripe/RequestOptions.php',
'Stripe_SingletonApiResource' => $vendorDir . '/stripe/stripe-php/lib/Stripe/SingletonApiResource.php',
'Stripe_Subscription' => $vendorDir . '/stripe/stripe-php/lib/Stripe/Subscription.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

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

9
vendor/composer/autoload_psr4.php vendored Normal file
View File

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

38
vendor/composer/autoload_real.php vendored Normal file
View File

@ -0,0 +1,38 @@
<?php
// autoload_real.php @generated by Composer
class ComposerAutoloaderInit40aa654f2e66c20881ae0572fe987a10
{
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('ComposerAutoloaderInit40aa654f2e66c20881ae0572fe987a10', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
spl_autoload_unregister(array('ComposerAutoloaderInit40aa654f2e66c20881ae0572fe987a10', 'loadClassLoader'));
require __DIR__ . '/autoload_static.php';
call_user_func(\Composer\Autoload\ComposerStaticInit40aa654f2e66c20881ae0572fe987a10::getInitializer($loader));
$loader->register(true);
return $loader;
}
}

58
vendor/composer/autoload_static.php vendored Normal file
View File

@ -0,0 +1,58 @@
<?php
// autoload_static.php @generated by Composer
namespace Composer\Autoload;
class ComposerStaticInit40aa654f2e66c20881ae0572fe987a10
{
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_ApplicationFee' => __DIR__ . '/..' . '/stripe/stripe-php/lib/Stripe/ApplicationFee.php',
'Stripe_ApplicationFeeRefund' => __DIR__ . '/..' . '/stripe/stripe-php/lib/Stripe/ApplicationFeeRefund.php',
'Stripe_AttachedObject' => __DIR__ . '/..' . '/stripe/stripe-php/lib/Stripe/AttachedObject.php',
'Stripe_AuthenticationError' => __DIR__ . '/..' . '/stripe/stripe-php/lib/Stripe/AuthenticationError.php',
'Stripe_Balance' => __DIR__ . '/..' . '/stripe/stripe-php/lib/Stripe/Balance.php',
'Stripe_BalanceTransaction' => __DIR__ . '/..' . '/stripe/stripe-php/lib/Stripe/BalanceTransaction.php',
'Stripe_BitcoinReceiver' => __DIR__ . '/..' . '/stripe/stripe-php/lib/Stripe/BitcoinReceiver.php',
'Stripe_BitcoinTransaction' => __DIR__ . '/..' . '/stripe/stripe-php/lib/Stripe/BitcoinTransaction.php',
'Stripe_Card' => __DIR__ . '/..' . '/stripe/stripe-php/lib/Stripe/Card.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_FileUpload' => __DIR__ . '/..' . '/stripe/stripe-php/lib/Stripe/FileUpload.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_RateLimitError' => __DIR__ . '/..' . '/stripe/stripe-php/lib/Stripe/RateLimitError.php',
'Stripe_Recipient' => __DIR__ . '/..' . '/stripe/stripe-php/lib/Stripe/Recipient.php',
'Stripe_Refund' => __DIR__ . '/..' . '/stripe/stripe-php/lib/Stripe/Refund.php',
'Stripe_RequestOptions' => __DIR__ . '/..' . '/stripe/stripe-php/lib/Stripe/RequestOptions.php',
'Stripe_SingletonApiResource' => __DIR__ . '/..' . '/stripe/stripe-php/lib/Stripe/SingletonApiResource.php',
'Stripe_Subscription' => __DIR__ . '/..' . '/stripe/stripe-php/lib/Stripe/Subscription.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 = ComposerStaticInit40aa654f2e66c20881ae0572fe987a10::$classMap;
}, null, ClassLoader::class);
}
}

61
vendor/composer/installed.json vendored Normal file
View File

@ -0,0 +1,61 @@
{
"packages": [
{
"name": "stripe/stripe-php",
"version": "v1.18.0",
"version_normalized": "1.18.0.0",
"source": {
"type": "git",
"url": "https://github.com/stripe/stripe-php.git",
"reference": "022c3f21ec1e4141b46738bd5e7ab730d04f78cc"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/stripe/stripe-php/zipball/022c3f21ec1e4141b46738bd5e7ab730d04f78cc",
"reference": "022c3f21ec1e4141b46738bd5e7ab730d04f78cc",
"shasum": ""
},
"require": {
"ext-curl": "*",
"ext-json": "*",
"ext-mbstring": "*",
"php": ">=5.2"
},
"require-dev": {
"simpletest/simpletest": "*"
},
"time": "2015-01-22T05:01:46+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/v1.18.0"
},
"install-path": "../stripe/stripe-php"
}
],
"dev": true,
"dev-package-names": []
}

32
vendor/composer/installed.php vendored Normal file
View File

@ -0,0 +1,32 @@
<?php return array(
'root' => array(
'name' => '__root__',
'pretty_version' => 'dev-master',
'version' => 'dev-master',
'reference' => '19ba6fb5813697276ca73413a3c4121b2d952eee',
'type' => 'library',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
'dev' => true,
),
'versions' => array(
'__root__' => array(
'pretty_version' => 'dev-master',
'version' => 'dev-master',
'reference' => '19ba6fb5813697276ca73413a3c4121b2d952eee',
'type' => 'library',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
'dev_requirement' => false,
),
'stripe/stripe-php' => array(
'pretty_version' => 'v1.18.0',
'version' => '1.18.0.0',
'reference' => '022c3f21ec1e4141b46738bd5e7ab730d04f78cc',
'type' => 'library',
'install_path' => __DIR__ . '/../stripe/stripe-php',
'aliases' => array(),
'dev_requirement' => false,
),
),
);

25
vendor/composer/platform_check.php vendored Normal file
View File

@ -0,0 +1,25 @@
<?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)
);
}

11
vendor/stripe/stripe-php/.gitignore vendored Normal file
View File

@ -0,0 +1,11 @@
# 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

17
vendor/stripe/stripe-php/.travis.yml vendored Normal file
View File

@ -0,0 +1,17 @@
language: php
php:
- 5.2
- 5.3
- 5.4
- 5.5
- 5.6
- hhvm
before_script:
- sh -c "if [ '$TRAVIS_PHP_VERSION' = '5.2' ]; then wget http://iweb.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; else composer install --dev --prefer-source; fi"
- sh -c "if [ '$TRAVIS_PHP_VERSION' = '5.6' ]; then pear install pear/PHP_CodeSniffer; phpenv rehash; fi"
script:
- sh -c "if [ '$TRAVIS_PHP_VERSION' = '5.6' ]; then phpcs --standard=zend --encoding=UTF-8 --ignore=vendor -p ./; fi"
- php test/Stripe.php

189
vendor/stripe/stripe-php/CHANGELOG vendored Normal file
View File

@ -0,0 +1,189 @@
=== 1.18.0 2015-01-21
* Support making bitcoin charges through BitcoinReceiver source object
=== 1.17.5 2014-12-23
* Adding support for creating file uploads.
=== 1.17.4 2014-12-15
* Saving objects fetched with a custom key now works (thanks @JustinHook & @jpasilan)
* Added methods for reporting charges as safe or fraudulent and for specifying the reason for refunds
=== 1.17.3 2014-11-06
* Better handling of HHVM support for SSL certificate blacklist checking.
=== 1.17.2 2014-09-23
* Coupons now are backed by a `Stripe_Coupon` instead of `Stripe_Object`, and support updating metadata
* Running operations (`create`, `retrieve`, `all`) on upcoming invoice items now works
=== 1.17.1 2014-07-31
* Requests now send Content-Type header
=== 1.17.0 2014-07-29
* Application Fee refunds now a list instead of array
* HHVM now works
* Small bug fixes (thanks @bencromwell & @fastest963)
* __toString now returns the name of the object in addition to its JSON representation
=== 1.16.0 2014-06-17
* Add metadata for refunds and disputes
=== 1.15.0 2014-05-28
* Support canceling transfers
=== 1.14.1 2014-05-21
* Support cards for recipients.
=== 1.13.1 2014-05-15
* Fix bug in account resource where `id` wasn't in the result
=== 1.13.0 2014-04-10
* Add support for certificate blacklisting
* Update ca bundle
* Drop support for HHVM (Temporarily)
=== 1.12.0 2014-04-01
* Add Stripe_RateLimitError for catching rate limit errors.
* Update to Zend coding style (thanks, @jpiasetz)
=== 1.11.0 2014-01-29
* Add support for multiple subscriptions per customer
=== 1.10.1 2013-12-02
* Add new ApplicationFee
=== 1.9.1 2013-11-08
* Fix a bug where a null nestable object causes warnings to fire.
=== 1.9.0 2013-10-16
* Add support for metadata API.
=== 1.8.4 2013-09-18
* Add support for closing disputes.
=== 1.8.3 2013-08-13
* Add new Balance and BalanceTransaction
=== 1.8.2 2013-08-12
* Add support for unsetting attributes by updating to NULL.
Setting properties to a blank string is now an error.
=== 1.8.1 2013-07-12
* Add support for multiple cards API (Stripe API version 2013-07-12: https://stripe.com/docs/upgrades#2013-07-05)
=== 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_SingletonApiRequest 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 resource 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

21
vendor/stripe/stripe-php/LICENSE vendored Normal file
View File

@ -0,0 +1,21 @@
The MIT License
Copyright (c) 2010-2014 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.

67
vendor/stripe/stripe-php/README.rdoc vendored Normal file
View File

@ -0,0 +1,67 @@
= Stripe PHP bindings
{<img src="https://travis-ci.org/stripe/stripe-php.svg?branch=master" alt="Build Status" />}[https://travis-ci.org/stripe/stripe-php]
{<img src="https://poser.pugx.org/stripe/stripe-php/v/stable.svg" alt="Latest Stable Version" />}[https://packagist.org/packages/stripe/stripe-php]
{<img src="https://poser.pugx.org/stripe/stripe-php/downloads.svg" alt="Total Downloads" />}[https://packagist.org/packages/stripe/stripe-php]
{<img src="https://poser.pugx.org/stripe/stripe-php/license.svg" alt="License" />}[https://packagist.org/packages/stripe/stripe-php]
You can sign up for a Stripe account at https://stripe.com.
== Requirements
PHP 5.2 and later.
== Composer
You can install the bindings via Composer[http://getcomposer.org/]. Add this to your +composer.json+:
{
"require": {
"stripe/stripe-php": "1.*"
}
}
Then install via:
composer.phar install
To use the bindings, either user Composer's autoload[https://getcomposer.org/doc/00-intro.md#autoloading]:
require_once('vendor/autoload.php');
Or manually:
require_once('/path/to/vendor/stripe/stripe-php/lib/Stripe.php');
== Manual Installation
Obtain the latest version of the Stripe PHP bindings with:
git clone https://github.com/stripe/stripe-php
To use the bindings, add the following to your PHP script:
require_once("/path/to/stripe-php/lib/Stripe.php");
== Getting Started
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/docs/api for up-to-date documentation.
== Tests
In order to run tests you have to install SimpleTest[http://packagist.org/packages/simpletest/simpletest] via Composer[http://getcomposer.org/] (recommended way):
composer.phar update --dev
Run test suite:
php ./test/Stripe.php

1
vendor/stripe/stripe-php/VERSION vendored Normal file
View File

@ -0,0 +1 @@
1.18.0

29
vendor/stripe/stripe-php/composer.json vendored Normal file
View File

@ -0,0 +1,29 @@
{
"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": "*",
"ext-json": "*",
"ext-mbstring": "*"
},
"require-dev": {
"simpletest/simpletest": "*"
},
"autoload": {
"classmap": ["lib/Stripe/"]
}
}

62
vendor/stripe/stripe-php/lib/Stripe.php vendored Normal file
View File

@ -0,0 +1,62 @@
<?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.');
}
if (!function_exists('mb_detect_encoding')) {
throw new Exception('Stripe needs the Multibyte String 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');
require(dirname(__FILE__) . '/Stripe/RateLimitError.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/AttachedObject.php');
require(dirname(__FILE__) . '/Stripe/List.php');
require(dirname(__FILE__) . '/Stripe/RequestOptions.php');
// Stripe API Resources
require(dirname(__FILE__) . '/Stripe/Account.php');
require(dirname(__FILE__) . '/Stripe/Card.php');
require(dirname(__FILE__) . '/Stripe/Balance.php');
require(dirname(__FILE__) . '/Stripe/BalanceTransaction.php');
require(dirname(__FILE__) . '/Stripe/Charge.php');
require(dirname(__FILE__) . '/Stripe/Customer.php');
require(dirname(__FILE__) . '/Stripe/FileUpload.php');
require(dirname(__FILE__) . '/Stripe/Invoice.php');
require(dirname(__FILE__) . '/Stripe/InvoiceItem.php');
require(dirname(__FILE__) . '/Stripe/Plan.php');
require(dirname(__FILE__) . '/Stripe/Subscription.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');
require(dirname(__FILE__) . '/Stripe/Refund.php');
require(dirname(__FILE__) . '/Stripe/ApplicationFee.php');
require(dirname(__FILE__) . '/Stripe/ApplicationFeeRefund.php');
require(dirname(__FILE__) . '/Stripe/BitcoinReceiver.php');
require(dirname(__FILE__) . '/Stripe/BitcoinTransaction.php');

View File

@ -0,0 +1,15 @@
<?php
class Stripe_Account extends Stripe_SingletonApiResource
{
/**
* @param string|null $apiKey
*
* @return Stripe_Account
*/
public static function retrieve($apiKey=null)
{
$class = get_class();
return self::_scopedSingletonRetrieve($class, $apiKey);
}
}

View File

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

View File

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

View File

@ -0,0 +1,462 @@
<?php
class Stripe_ApiRequestor
{
private $_apiKey;
private $_apiBase;
private static $_preFlight = array();
private static $_blacklistedCerts = array(
'05c0b3643694470a888c6e7feb5c9e24e823dc53',
'5b7dc7fbc98d78bf76d4d4fa6f597a0c901fad5c',
);
public function __construct($apiKey=null, $apiBase=null)
{
$this->_apiKey = $apiKey;
if (!$apiBase) {
$apiBase = Stripe::$apiBase;
}
$this->_apiBase = $apiBase;
}
/**
* @param string|mixed $value A string to UTF8-encode.
*
* @returns string|mixed The UTF8-encoded string, or the object passed in if
* it wasn't a string.
*/
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);
}
}
/**
* @param array $arr An map of param keys to values.
* @param string|null $prefix (It doesn't look like we ever use $prefix...)
*
* @returns string A querystring, essentially.
*/
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);
}
/**
* @param string $method
* @param string $url
* @param array|null $params
* @param array|null $headers
*
* @return array An array whose first element is the response and second
* element is the API key used to make the request.
*/
public function request($method, $url, $params=null, $headers=null)
{
if (!$params) {
$params = array();
}
if (!$headers) {
$headers = array();
}
list($rbody, $rcode, $myApiKey) =
$this->_requestRaw($method, $url, $params, $headers);
$resp = $this->_interpretResponse($rbody, $rcode);
return array($resp, $myApiKey);
}
/**
* @param string $rbody A JSON string.
* @param int $rcode
* @param array $resp
*
* @throws Stripe_InvalidRequestError if the error is caused by the user.
* @throws Stripe_AuthenticationError if the error is caused by a lack of
* permissions.
* @throws Stripe_CardError if the error is the error code is 402 (payment
* required)
* @throws Stripe_ApiError otherwise.
*/
public function handleApiError($rbody, $rcode, $resp)
{
if (!is_array($resp) || !isset($resp['error'])) {
$msg = "Invalid response object from API: $rbody "
."(HTTP response code was $rcode)";
throw new Stripe_ApiError($msg, $rcode, $rbody, $resp);
}
$error = $resp['error'];
$msg = isset($error['message']) ? $error['message'] : null;
$param = isset($error['param']) ? $error['param'] : null;
$code = isset($error['code']) ? $error['code'] : null;
switch ($rcode) {
case 400:
if ($code == 'rate_limit') {
throw new Stripe_RateLimitError(
$msg, $param, $rcode, $rbody, $resp
);
}
case 404:
throw new Stripe_InvalidRequestError(
$msg, $param, $rcode, $rbody, $resp
);
case 401:
throw new Stripe_AuthenticationError($msg, $rcode, $rbody, $resp);
case 402:
throw new Stripe_CardError($msg, $param, $code, $rcode, $rbody, $resp);
default:
throw new Stripe_ApiError($msg, $rcode, $rbody, $resp);
}
}
private function _requestRaw($method, $url, $params, $headers)
{
if (!array_key_exists($this->_apiBase, self::$_preFlight)
|| !self::$_preFlight[$this->_apiBase]) {
self::$_preFlight[$this->_apiBase] = $this->checkSslCert($this->_apiBase);
}
$myApiKey = $this->_apiKey;
if (!$myApiKey) {
$myApiKey = Stripe::$apiKey;
}
if (!$myApiKey) {
$msg = '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.';
throw new Stripe_AuthenticationError($msg);
}
$absUrl = $this->_apiBase.$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,
);
$defaultHeaders = array(
'X-Stripe-Client-User-Agent' => json_encode($ua),
'User-Agent' => 'Stripe/v1 PhpBindings/' . Stripe::VERSION,
'Authorization' => 'Bearer ' . $myApiKey,
);
if (Stripe::$apiVersion) {
$defaultHeaders['Stripe-Version'] = Stripe::$apiVersion;
}
$hasFile = false;
$hasCurlFile = class_exists('CURLFile', false);
foreach ($params as $k => $v) {
if (is_resource($v)) {
$hasFile = true;
$params[$k] = self::_processResourceParam($v, $hasCurlFile);
} else if ($hasCurlFile && $v instanceof CURLFile) {
$hasFile = true;
}
}
if ($hasFile) {
$defaultHeaders['Content-Type'] = 'multipart/form-data';
} else {
$defaultHeaders['Content-Type'] = 'application/x-www-form-urlencoded';
}
$combinedHeaders = array_merge($defaultHeaders, $headers);
$rawHeaders = array();
foreach ($combinedHeaders as $header => $value) {
$rawHeaders[] = $header . ': ' . $value;
}
list($rbody, $rcode) = $this->_curlRequest(
$method,
$absUrl,
$rawHeaders,
$params,
$hasFile
);
return array($rbody, $rcode, $myApiKey);
}
private function _processResourceParam($resource, $hasCurlFile)
{
if (get_resource_type($resource) !== 'stream') {
throw new Stripe_ApiError(
'Attempted to upload a resource that is not a stream'
);
}
$metaData = stream_get_meta_data($resource);
if ($metaData['wrapper_type'] !== 'plainfile') {
throw new Stripe_ApiError(
'Only plainfile resource streams are supported'
);
}
if ($hasCurlFile) {
// We don't have the filename or mimetype, but the API doesn't care
return new CURLFile($metaData['uri']);
} else {
return '@'.$metaData['uri'];
}
}
private function _interpretResponse($rbody, $rcode)
{
try {
$resp = json_decode($rbody, true);
} catch (Exception $e) {
$msg = "Invalid response body from API: $rbody "
. "(HTTP response code was $rcode)";
throw new Stripe_ApiError($msg, $rcode, $rbody);
}
if ($rcode < 200 || $rcode >= 300) {
$this->handleApiError($rbody, $rcode, $resp);
}
return $resp;
}
private function _curlRequest($method, $absUrl, $headers, $params, $hasFile)
{
$curl = curl_init();
$method = strtolower($method);
$opts = array();
if ($method == 'get') {
if ($hasFile) {
throw new Stripe_ApiError(
"Issuing a GET request with a file parameter"
);
}
$opts[CURLOPT_HTTPGET] = 1;
if (count($params) > 0) {
$encoded = self::encode($params);
$absUrl = "$absUrl?$encoded";
}
} else if ($method == 'post') {
$opts[CURLOPT_POST] = 1;
$opts[CURLOPT_POSTFIELDS] = $hasFile ? $params : self::encode($params);
} else if ($method == 'delete') {
$opts[CURLOPT_CUSTOMREQUEST] = 'DELETE';
if (count($params) > 0) {
$encoded = self::encode($params);
$absUrl = "$absUrl?$encoded";
}
} else {
throw new Stripe_ApiError("Unrecognized method $method");
}
$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);
if (!defined('CURLE_SSL_CACERT_BADFILE')) {
define('CURLE_SSL_CACERT_BADFILE', 77); // constant not defined in PHP
}
$errno = curl_errno($curl);
if ($errno == CURLE_SSL_CACERT ||
$errno == CURLE_SSL_PEER_CERTIFICATE ||
$errno == CURLE_SSL_CACERT_BADFILE) {
array_push(
$headers,
'X-Stripe-Client-Info: {"ca":"using Stripe-supplied CA bundle"}'
);
$cert = $this->caBundle();
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
curl_setopt($curl, CURLOPT_CAINFO, $cert);
$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);
}
/**
* @param number $errno
* @param string $message
* @throws Stripe_ApiConnectionError
*/
public function handleCurlError($errno, $message)
{
$apiBase = $this->_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";
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,";
break;
default:
$msg = "Unexpected error communicating with Stripe. "
. "If this problem persists,";
}
$msg .= " let us know at support@stripe.com.";
$msg .= "\n\n(Network error [errno $errno]: $message)";
throw new Stripe_ApiConnectionError($msg);
}
/**
* Preflight the SSL certificate presented by the backend. This isn't 100%
* bulletproof, in that we're not actually validating the transport used to
* communicate with Stripe, merely that the first attempt to does not use a
* revoked certificate.
*
* Unfortunately the interface to OpenSSL doesn't make it easy to check the
* certificate before sending potentially sensitive data on the wire. This
* approach raises the bar for an attacker significantly.
*/
private function checkSslCert($url)
{
if (!function_exists('stream_context_get_params') ||
!function_exists('stream_socket_enable_crypto')) {
error_log(
'Warning: This version of PHP does not support checking SSL '.
'certificates Stripe cannot guarantee that the server has a '.
'certificate which is not blacklisted.'
);
return true;
}
$url = parse_url($url);
$port = isset($url["port"]) ? $url["port"] : 443;
$url = "ssl://{$url["host"]}:{$port}";
$sslContext = stream_context_create(
array('ssl' => array(
'capture_peer_cert' => true,
'verify_peer' => true,
'cafile' => $this->caBundle(),
))
);
$result = stream_socket_client(
$url, $errno, $errstr, 30, STREAM_CLIENT_CONNECT, $sslContext
);
if (($errno !== 0 && $errno !== NULL) || $result === false) {
throw new Stripe_ApiConnectionError(
'Could not connect to Stripe (' . $url . '). Please check your '.
'internet connection and try again. If this problem persists, '.
'you should check Stripe\'s service status at '.
'https://twitter.com/stripestatus. Reason was: '.$errstr
);
}
$params = stream_context_get_params($result);
$cert = $params['options']['ssl']['peer_certificate'];
openssl_x509_export($cert, $pemCert);
if (self::isBlackListed($pemCert)) {
throw new Stripe_ApiConnectionError(
'Invalid server certificate. You tried to connect to a server that '.
'has a revoked SSL certificate, which means we cannot securely send '.
'data to that server. Please email support@stripe.com if you need '.
'help connecting to the correct API server.'
);
}
return true;
}
/* Checks if a valid PEM encoded certificate is blacklisted
* @return boolean
*/
public static function isBlackListed($certificate)
{
$certificate = trim($certificate);
$lines = explode("\n", $certificate);
// Kludgily remove the PEM padding
array_shift($lines); array_pop($lines);
$derCert = base64_decode(implode("", $lines));
$fingerprint = sha1($derCert);
return in_array($fingerprint, self::$_blacklistedCerts);
}
private function caBundle()
{
return dirname(__FILE__) . '/../data/ca-certificates.crt';
}
}

View File

@ -0,0 +1,174 @@
<?php
abstract class Stripe_ApiResource extends Stripe_Object
{
public static function baseUrl()
{
return Stripe::$apiBase;
}
protected static function _scopedRetrieve($class, $id, $options=null)
{
$opts = Stripe_RequestOptions::parse($options);
$instance = new $class($id, $opts->apiKey);
$instance->refresh();
return $instance;
}
/**
* @returns Stripe_ApiResource The refreshed resource.
*/
public function refresh()
{
$requestor = new Stripe_ApiRequestor($this->_apiKey, self::baseUrl());
$url = $this->instanceUrl();
list($response, $apiKey) = $requestor->request(
'get',
$url,
$this->_retrieveOptions
);
$this->refreshFrom($response, $apiKey);
return $this;
}
/**
* @param array options
*
* @returns Stripe_RequestOptions with either passed in or saved API key
*/
public function parseOptions($options)
{
$opts = Stripe_RequestOptions::parse($options);
$key = ($opts->apiKey ? $opts->apiKey : $this->_apiKey);
$opts->apiKey = $key;
return $opts;
}
/**
* @param string $class
*
* @returns string The name of the class, with namespacing and underscores
* stripped.
*/
public static function className($class)
{
// Useful for namespaces: Foo\Stripe_Charge
if ($postfixNamespaces = strrchr($class, '\\')) {
$class = substr($postfixNamespaces, 1);
}
// Useful for underscored 'namespaces': Foo_Stripe_Charge
if ($postfixFakeNamespaces = strrchr($class, 'Stripe_')) {
$class = $postfixFakeNamespaces;
}
if (substr($class, 0, strlen('Stripe')) == 'Stripe') {
$class = substr($class, strlen('Stripe'));
}
$class = str_replace('_', '', $class);
$name = urlencode($class);
$name = strtolower($name);
return $name;
}
/**
* @param string $class
*
* @returns string The endpoint URL for the given class.
*/
public static function classUrl($class)
{
$base = self::_scopedLsb($class, 'className', $class);
return "/v1/${base}s";
}
/**
* @returns string The full API URL for this API resource.
*/
public function instanceUrl()
{
$id = $this['id'];
$class = get_class($this);
if ($id === null) {
$message = "Could not determine which URL to request: "
. "$class instance has invalid ID: $id";
throw new Stripe_InvalidRequestError($message, null);
}
$id = Stripe_ApiRequestor::utf8($id);
$base = $this->_lsb('classUrl', $class);
$extn = urlencode($id);
return "$base/$extn";
}
private static function _validateCall($method, $params=null, $options=null)
{
if ($params && !is_array($params)) {
$message = "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)))\")";
throw new Stripe_Error($message);
}
if ($options && (!is_string($options) && !is_array($options))) {
$message = 'The second argument to Stripe API method calls is an '
. 'optional per-request apiKey, which must be a string, or '
. 'per-request options, which must be an array. '
. '(HINT: you can set a global apiKey by '
. '"Stripe::setApiKey(<apiKey>)")';
throw new Stripe_Error($message);
}
}
protected static function _scopedAll($class, $params=null, $options=null)
{
self::_validateCall('all', $params, $options);
$base = self::_scopedLsb($class, 'baseUrl');
$url = self::_scopedLsb($class, 'classUrl', $class);
$opts = Stripe_RequestOptions::parse($options);
$requestor = new Stripe_ApiRequestor($opts->apiKey, $base);
list($response, $apiKey) =
$requestor->request('get', $url, $params, $opts->headers);
return Stripe_Util::convertToStripeObject($response, $apiKey);
}
protected static function _scopedCreate($class, $params=null, $options=null)
{
self::_validateCall('create', $params, $options);
$opts = Stripe_RequestOptions::parse($options);
$base = self::_scopedLsb($class, 'baseUrl');
$requestor = new Stripe_ApiRequestor($opts->apiKey, $base);
$url = self::_scopedLsb($class, 'classUrl', $class);
list($response, $apiKey) =
$requestor->request('post', $url, $params, $opts->headers);
return Stripe_Util::convertToStripeObject($response, $apiKey);
}
protected function _scopedSave($class, $options=null)
{
self::_validateCall('save', null, $options);
$opts = Stripe_RequestOptions::parse($options);
$key = ($opts->apiKey ? $opts->apiKey : $this->_apiKey);
$requestor = new Stripe_ApiRequestor($key, self::baseUrl());
$params = $this->serializeParameters();
if (count($params) > 0) {
$url = $this->instanceUrl();
list($response, $apiKey) = $requestor->request('post', $url, $params);
$this->refreshFrom($response, $apiKey);
}
return $this;
}
protected function _scopedDelete($class, $params=null, $options=null)
{
self::_validateCall('delete', $params, $options);
$opts = Stripe_RequestOptions::parse($options);
$key = ($opts->apiKey ? $opts->apiKey : $this->_apiKey);
$requestor = new Stripe_ApiRequestor($key, self::baseUrl());
$url = $this->instanceUrl();
list($response, $apiKey) = $requestor->request('delete', $url, $params);
$this->refreshFrom($response, $apiKey);
return $this;
}
}

View File

@ -0,0 +1,53 @@
<?php
class Stripe_ApplicationFee extends Stripe_ApiResource
{
/**
* This is a special case because the application fee endpoint has an
* underscore in it. The parent `className` function strips underscores.
*
* @return string The name of the class.
*/
public static function className($class)
{
return 'application_fee';
}
/**
* @param string $id The ID of the application fee to retrieve.
* @param string|null $apiKey
*
* @return Stripe_ApplicationFee
*/
public static function retrieve($id, $apiKey=null)
{
$class = get_class();
return self::_scopedRetrieve($class, $id, $apiKey);
}
/**
* @param string|null $params
* @param string|null $apiKey
*
* @return array An array of application fees.
*/
public static function all($params=null, $apiKey=null)
{
$class = get_class();
return self::_scopedAll($class, $params, $apiKey);
}
/**
* @param string|null $params
*
* @return Stripe_ApplicationFee The refunded application fee.
*/
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;
}
}

View File

@ -0,0 +1,36 @@
<?php
class Stripe_ApplicationFeeRefund extends Stripe_ApiResource
{
/**
* @return string The API URL for this Stripe refund.
*/
public function instanceUrl()
{
$id = $this['id'];
$fee = $this['fee'];
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);
$fee = Stripe_ApiRequestor::utf8($fee);
$base = self::classUrl('Stripe_ApplicationFee');
$feeExtn = urlencode($fee);
$extn = urlencode($id);
return "$base/$feeExtn/refunds/$extn";
}
/**
* @return Stripe_ApplicationFeeRefund The saved refund.
*/
public function save()
{
$class = get_class();
return self::_scopedSave($class);
}
}

View File

@ -0,0 +1,23 @@
<?php
// e.g. metadata on Stripe objects.
class Stripe_AttachedObject extends Stripe_Object
{
/**
* Updates this object.
*
* @param array $properties A mapping of properties to update on this object.
*/
public function replaceWith($properties)
{
$removed = array_diff(array_keys($this->_values), array_keys($properties));
// Don't unset, but rather set to null so we send up '' for deletion.
foreach ($removed as $k) {
$this->$k = null;
}
foreach ($properties as $k => $v) {
$this->$k = $v;
}
}
}

View File

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

View File

@ -0,0 +1,15 @@
<?php
class Stripe_Balance extends Stripe_SingletonApiResource
{
/**
* @param string|null $apiKey
*
* @return Stripe_Balance
*/
public static function retrieve($apiKey=null)
{
$class = get_class();
return self::_scopedSingletonRetrieve($class, $apiKey);
}
}

View File

@ -0,0 +1,39 @@
<?php
class Stripe_BalanceTransaction extends Stripe_ApiResource
{
/**
* @param string $class Ignored.
*
* @return string The class URL for this resource. It needs to be special
* cased because it doesn't fit into the standard resource pattern.
*/
public static function classUrl($class)
{
return "/v1/balance/history";
}
/**
* @param string $id The ID of the balance transaction to retrieve.
* @param string|null $apiKey
*
* @return Stripe_BalanceTransaction
*/
public static function retrieve($id, $apiKey=null)
{
$class = get_class();
return self::_scopedRetrieve($class, $id, $apiKey);
}
/**
* @param array|null $params
* @param string|null $apiKey
*
* @return array An array of Stripe_BalanceTransactions.
*/
public static function all($params=null, $apiKey=null)
{
$class = get_class();
return self::_scopedAll($class, $params, $apiKey);
}
}

View File

@ -0,0 +1,61 @@
<?php
class Stripe_BitcoinReceiver extends Stripe_ApiResource
{
/**
* @param string $class Ignored.
*
* @return string The class URL for this resource. It needs to be special
* cased because it doesn't fit into the standard resource pattern.
*/
public static function classUrl($class)
{
return "/v1/bitcoin/receivers";
}
/**
* @param string $id The ID of the Bitcoin Receiver to retrieve.
* @param string|null $apiKey
*
* @return Stripe_BitcoinReceiver
*/
public static function retrieve($id, $apiKey=null)
{
$class = get_class();
return self::_scopedRetrieve($class, $id, $apiKey);
}
/**
* @param array|null $params
* @param string|null $apiKey
*
* @return array An array of Stripe_BitcoinReceivers.
*/
public static function all($params=null, $apiKey=null)
{
$class = get_class();
return self::_scopedAll($class, $params, $apiKey);
}
/**
* @param array|null $params
* @param string|null $apiKey
*
* @return Stripe_BitcoinReceiver The created Bitcoin Receiver item.
*/
public static function create($params=null, $apiKey=null)
{
$class = get_class();
return self::_scopedCreate($class, $params, $apiKey);
}
/**
* @return Stripe_BitcoinReceiver The saved Bitcoin Receiver item.
*/
public function save()
{
$class = get_class();
return self::_scopedSave($class);
}
}

View File

@ -0,0 +1,7 @@
<?php
class Stripe_BitcoinTransaction extends Stripe_ApiResource
{
}

View File

@ -0,0 +1,66 @@
<?php
class Stripe_Card extends Stripe_ApiResource
{
public static function constructFrom($values, $apiKey=null)
{
$class = get_class();
return self::scopedConstructFrom($class, $values, $apiKey);
}
/**
* @return string The instance URL for this resource. It needs to be special
* cased because it doesn't fit into the standard resource pattern.
*/
public function instanceUrl()
{
$id = $this['id'];
if (!$id) {
$class = get_class($this);
$msg = "Could not determine which URL to request: $class instance "
. "has invalid ID: $id";
throw new Stripe_InvalidRequestError($msg, null);
}
if (isset($this['customer'])) {
$parent = $this['customer'];
$base = self::classUrl('Stripe_Customer');
} else if (isset($this['recipient'])) {
$parent = $this['recipient'];
$base = self::classUrl('Stripe_Recipient');
} else {
return null;
}
$parent = Stripe_ApiRequestor::utf8($parent);
$id = Stripe_ApiRequestor::utf8($id);
$parentExtn = urlencode($parent);
$extn = urlencode($id);
return "$base/$parentExtn/cards/$extn";
}
/**
* @param array|null $params
*
* @return Stripe_Card The deleted card.
*/
public function delete($params=null)
{
$class = get_class();
return self::_scopedDelete($class, $params);
}
/**
* @return Stripe_Card The saved card.
*/
public function save()
{
$class = get_class();
return self::_scopedSave($class);
}
}

View File

@ -0,0 +1,13 @@
<?php
class Stripe_CardError extends Stripe_Error
{
public function __construct($message, $param, $code, $httpStatus,
$httpBody, $jsonBody
)
{
parent::__construct($message, $httpStatus, $httpBody, $jsonBody);
$this->param = $param;
$this->code = $code;
}
}

View File

@ -0,0 +1,137 @@
<?php
class Stripe_Charge extends Stripe_ApiResource
{
/**
* @param string $id The ID of the charge to retrieve.
* @param string|null $apiKey
*
* @return Stripe_Charge
*/
public static function retrieve($id, $options=null)
{
$class = get_class();
return self::_scopedRetrieve($class, $id, $options);
}
/**
* @param array|null $params
* @param string|null $apiKey
*
* @return array An array of Stripe_Charges.
*/
public static function all($params=null, $options=null)
{
$class = get_class();
return self::_scopedAll($class, $params, $options);
}
/**
* @param array|null $params
* @param string|null $apiKey
*
* @return Stripe_Charge The created charge.
*/
public static function create($params=null, $options=null)
{
$class = get_class();
return self::_scopedCreate($class, $params, $options);
}
/**
* @return Stripe_Charge The saved charge.
*/
public function save($options=null)
{
$class = get_class();
return self::_scopedSave($class, $options);
}
/**
* @param array|null $params
*
* @return Stripe_Charge The refunded charge.
*/
public function refund($params=null, $options=null)
{
$opts = $this->parseOptions($options);
$requestor = new Stripe_ApiRequestor($opts->apiKey);
$url = $this->instanceUrl() . '/refund';
list($response, $apiKey) =
$requestor->request('post', $url, $params, $opts->headers);
$this->refreshFrom($response, $apiKey);
return $this;
}
/**
* @param array|null $params
*
* @return Stripe_Charge The captured charge.
*/
public function capture($params=null, $options=null)
{
$opts = $this->parseOptions($options);
$requestor = new Stripe_ApiRequestor($opts->apiKey);
$url = $this->instanceUrl() . '/capture';
list($response, $apiKey) =
$requestor->request('post', $url, $params, $opts->headers);
$this->refreshFrom($response, $apiKey);
return $this;
}
/**
* @param array|null $params
*
* @return array The updated dispute.
*/
public function updateDispute($params=null, $option=null)
{
$opts = $this->parseOptions($options);
$requestor = new Stripe_ApiRequestor($opts->apiKey);
$url = $this->instanceUrl() . '/dispute';
list($response, $apiKey) =
$requestor->request('post', $url, $params, $headers);
$this->refreshFrom(array('dispute' => $response), $apiKey, true);
return $this->dispute;
}
/**
* @return Stripe_Charge The updated charge.
*/
public function closeDispute($options=null)
{
$opts = $this->parseOptions($options);
$requestor = new Stripe_ApiRequestor($opts->apiKey);
$url = $this->instanceUrl() . '/dispute/close';
list($response, $apiKey) =
$requestor->request('post', $url, null, $opts->headers);
$this->refreshFrom($response, $apiKey);
return $this;
}
/**
* @return Stripe_Charge The updated charge.
*/
public function markAsFraudulent()
{
$params = array('fraud_details' => array('user_report' => 'fraudulent'));
$requestor = new Stripe_ApiRequestor($this->_apiKey);
$url = $this->instanceUrl();
list($response, $apiKey) = $requestor->request('post', $url, $params);
$this->refreshFrom($response, $apiKey);
return $this;
}
/**
* @return Stripe_Charge The updated charge.
*/
public function markAsSafe()
{
$params = array('fraud_details' => array('user_report' => 'safe'));
$requestor = new Stripe_ApiRequestor($this->_apiKey);
$url = $this->instanceUrl();
list($response, $apiKey) = $requestor->request('post', $url, $params);
$this->refreshFrom($response, $apiKey);
return $this;
}
}

View File

@ -0,0 +1,60 @@
<?php
class Stripe_Coupon extends Stripe_ApiResource
{
/**
* @param string $id The ID of the coupon to retrieve.
* @param string|null $apiKey
*
* @return Stripe_Coupon
*/
public static function retrieve($id, $apiKey=null)
{
$class = get_class();
return self::_scopedRetrieve($class, $id, $apiKey);
}
/**
* @param array|null $params
* @param string|null $apiKey
*
* @return Stripe_Coupon The created coupon.
*/
public static function create($params=null, $apiKey=null)
{
$class = get_class();
return self::_scopedCreate($class, $params, $apiKey);
}
/**
* @param array|null $params
*
* @return Stripe_Coupon The deleted coupon.
*/
public function delete($params=null)
{
$class = get_class();
return self::_scopedDelete($class, $params);
}
/**
* @return Stripe_Coupon The saved coupon.
*/
public function save()
{
$class = get_class();
return self::_scopedSave($class);
}
/**
* @param array|null $params
* @param string|null $apiKey
*
* @return array An array of Stripe_Coupons.
*/
public static function all($params=null, $apiKey=null)
{
$class = get_class();
return self::_scopedAll($class, $params, $apiKey);
}
}

View File

@ -0,0 +1,157 @@
<?php
class Stripe_Customer extends Stripe_ApiResource
{
/**
* @param string $id The ID of the customer to retrieve.
* @param string|null $apiKey
*
* @return Stripe_Customer
*/
public static function retrieve($id, $apiKey=null)
{
$class = get_class();
return self::_scopedRetrieve($class, $id, $apiKey);
}
/**
* @param array|null $params
* @param string|null $apiKey
*
* @return array An array of Stripe_Customers.
*/
public static function all($params=null, $apiKey=null)
{
$class = get_class();
return self::_scopedAll($class, $params, $apiKey);
}
/**
* @param array|null $params
* @param string|null $apiKey
*
* @return Stripe_Customer The created customer.
*/
public static function create($params=null, $apiKey=null)
{
$class = get_class();
return self::_scopedCreate($class, $params, $apiKey);
}
/**
* @returns Stripe_Customer The saved customer.
*/
public function save()
{
$class = get_class();
return self::_scopedSave($class);
}
/**
* @param array|null $params
*
* @returns Stripe_Customer The deleted customer.
*/
public function delete($params=null)
{
$class = get_class();
return self::_scopedDelete($class, $params);
}
/**
* @param array|null $params
*
* @returns Stripe_InvoiceItem The resulting invoice item.
*/
public function addInvoiceItem($params=null)
{
if (!$params)
$params = array();
$params['customer'] = $this->id;
$ii = Stripe_InvoiceItem::create($params, $this->_apiKey);
return $ii;
}
/**
* @param array|null $params
*
* @returns array An array of the customer's Stripe_Invoices.
*/
public function invoices($params=null)
{
if (!$params)
$params = array();
$params['customer'] = $this->id;
$invoices = Stripe_Invoice::all($params, $this->_apiKey);
return $invoices;
}
/**
* @param array|null $params
*
* @returns array An array of the customer's Stripe_InvoiceItems.
*/
public function invoiceItems($params=null)
{
if (!$params)
$params = array();
$params['customer'] = $this->id;
$iis = Stripe_InvoiceItem::all($params, $this->_apiKey);
return $iis;
}
/**
* @param array|null $params
*
* @returns array An array of the customer's Stripe_Charges.
*/
public function charges($params=null)
{
if (!$params)
$params = array();
$params['customer'] = $this->id;
$charges = Stripe_Charge::all($params, $this->_apiKey);
return $charges;
}
/**
* @param array|null $params
*
* @returns Stripe_Subscription The updated subscription.
*/
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;
}
/**
* @param array|null $params
*
* @returns Stripe_Subscription The cancelled 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;
}
/**
* @param array|null $params
*
* @returns Stripe_Customer The updated customer.
*/
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

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

View File

@ -0,0 +1,28 @@
<?php
class Stripe_Event extends Stripe_ApiResource
{
/**
* @param string $id The ID of the event to retrieve.
* @param string|null $apiKey
*
* @return Stripe_Event
*/
public static function retrieve($id, $apiKey=null)
{
$class = get_class();
return self::_scopedRetrieve($class, $id, $apiKey);
}
/**
* @param array|null $params
* @param string|null $apiKey
*
* @return array An array of Stripe_Events.
*/
public static function all($params=null, $apiKey=null)
{
$class = get_class();
return self::_scopedAll($class, $params, $apiKey);
}
}

View File

@ -0,0 +1,50 @@
<?php
class Stripe_FileUpload extends Stripe_ApiResource
{
public static function baseUrl()
{
return Stripe::$apiUploadBase;
}
public static function className($class)
{
return 'file';
}
/**
* @param string $id The ID of the file upload to retrieve.
* @param string|null $apiKey
*
* @return Stripe_FileUpload
*/
public static function retrieve($id, $apiKey=null)
{
$class = get_class();
return self::_scopedRetrieve($class, $id, $apiKey);
}
/**
* @param array|null $params
* @param string|null $apiKey
*
* @return Stripe_FileUpload The created file upload.
*/
public static function create($params=null, $apiKey=null)
{
$class = get_class();
return self::_scopedCreate($class, $params, $apiKey);
}
/**
* @param array|null $params
* @param string|null $apiKey
*
* @return array An array of Stripe_FileUploads
*/
public static function all($params=null, $apiKey=null)
{
$class = get_class();
return self::_scopedAll($class, $params, $apiKey);
}
}

View File

@ -0,0 +1,12 @@
<?php
class Stripe_InvalidRequestError extends Stripe_Error
{
public function __construct($message, $param, $httpStatus=null,
$httpBody=null, $jsonBody=null
)
{
parent::__construct($message, $httpStatus, $httpBody, $jsonBody);
$this->param = $param;
}
}

View File

@ -0,0 +1,75 @@
<?php
class Stripe_Invoice extends Stripe_ApiResource
{
/**
* @param array|null $params
* @param string|null $apiKey
*
* @return Stripe_Invoice The created invoice.
*/
public static function create($params=null, $apiKey=null)
{
$class = get_class();
return self::_scopedCreate($class, $params, $apiKey);
}
/**
* @param string $id The ID of the invoice to retrieve.
* @param string|null $apiKey
*
* @return Stripe_Invoice
*/
public static function retrieve($id, $apiKey=null)
{
$class = get_class();
return self::_scopedRetrieve($class, $id, $apiKey);
}
/**
* @param array|null $params
* @param string|null $apiKey
*
* @return array An array of Stripe_Invoices.
*/
public static function all($params=null, $apiKey=null)
{
$class = get_class();
return self::_scopedAll($class, $params, $apiKey);
}
/**
* @param array|null $params
* @param string|null $apiKey
*
* @return Stripe_Invoice The upcoming invoice.
*/
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);
}
/**
* @return Stripe_Invoice The saved invoice.
*/
public function save()
{
$class = get_class();
return self::_scopedSave($class);
}
/**
* @return Stripe_Invoice The paid invoice.
*/
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

@ -0,0 +1,58 @@
<?php
class Stripe_InvoiceItem extends Stripe_ApiResource
{
/**
* @param string $id The ID of the invoice item to retrieve.
* @param string|null $apiKey
*
* @return Stripe_InvoiceItem
*/
public static function retrieve($id, $apiKey=null)
{
$class = get_class();
return self::_scopedRetrieve($class, $id, $apiKey);
}
/**
* @param array|null $params
* @param string|null $apiKey
*
* @return array An array of Stripe_InvoiceItems.
*/
public static function all($params=null, $apiKey=null)
{
$class = get_class();
return self::_scopedAll($class, $params, $apiKey);
}
/**
* @param array|null $params
* @param string|null $apiKey
*
* @return Stripe_InvoiceItem The created invoice item.
*/
public static function create($params=null, $apiKey=null)
{
$class = get_class();
return self::_scopedCreate($class, $params, $apiKey);
}
/**
* @return Stripe_InvoiceItem The saved invoice item.
*/
public function save()
{
$class = get_class();
return self::_scopedSave($class);
}
/**
* @return Stripe_InvoiceItem The deleted invoice item.
*/
public function delete($params=null)
{
$class = get_class();
return self::_scopedDelete($class, $params);
}
}

View File

@ -0,0 +1,54 @@
<?php
class Stripe_List extends Stripe_Object
{
public function all($params=null)
{
list($url, $params) = $this->extractPathAndUpdateParams($params);
$requestor = new Stripe_ApiRequestor($this->_apiKey);
list($response, $apiKey) = $requestor->request('get', $url, $params);
return Stripe_Util::convertToStripeObject($response, $apiKey);
}
public function create($params=null)
{
list($url, $params) = $this->extractPathAndUpdateParams($params);
$requestor = new Stripe_ApiRequestor($this->_apiKey);
list($response, $apiKey) = $requestor->request('post', $url, $params);
return Stripe_Util::convertToStripeObject($response, $apiKey);
}
public function retrieve($id, $params=null)
{
list($url, $params) = $this->extractPathAndUpdateParams($params);
$requestor = new Stripe_ApiRequestor($this->_apiKey);
$id = Stripe_ApiRequestor::utf8($id);
$extn = urlencode($id);
list($response, $apiKey) = $requestor->request(
'get', "$url/$extn", $params
);
return Stripe_Util::convertToStripeObject($response, $apiKey);
}
private function extractPathAndUpdateParams($params)
{
$url = parse_url($this->url);
if (!isset($url['path'])) {
throw new Stripe_APIError("Could not parse list url into parts: $url");
}
if (isset($url['query'])) {
// If the URL contains a query param, parse it out into $params so they
// don't interact weirdly with each other.
$query = array();
parse_str($url['query'], $query);
// PHP 5.2 doesn't support the ?: operator :(
$params = array_merge($params ? $params : array(), $query);
}
return array($url['path'], $params);
}
}

View File

@ -0,0 +1,265 @@
<?php
class Stripe_Object implements ArrayAccess
{
/**
* @var Stripe_Util_Set Attributes that should not be sent to the API because
* they're not updatable (e.g. API key, ID).
*/
public static $permanentAttributes;
/**
* @var Stripe_Util_Set Attributes that are nested but still updatable from
* the parent class's URL (e.g. metadata).
*/
public static $nestedUpdatableAttributes;
public static function init()
{
self::$permanentAttributes = new Stripe_Util_Set(array('_apiKey', 'id'));
self::$nestedUpdatableAttributes = new Stripe_Util_Set(array('metadata'));
}
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 !== null) {
$this->id = $id;
}
}
// Standard accessor magic methods
public function __set($k, $v)
{
if ($v === "") {
throw new InvalidArgumentException(
'You cannot set \''.$k.'\'to an empty string. '
.'We interpret empty strings as NULL in requests. '
.'You may set obj->'.$k.' = NULL to delete the property'
);
}
if (self::$nestedUpdatableAttributes->includes($k)
&& isset($this->$k) && is_array($v)) {
$this->$k->replaceWith($v);
} else {
// 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));
$message = "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";
error_log($message);
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;
}
public function keys()
{
return array_keys($this->_values);
}
/**
* This unfortunately needs to be public to be used in Util.php
*
* @param string $class
* @param array $values
* @param string|null $apiKey
*
* @return Stripe_Object The object constructed from the given values.
*/
public static function scopedConstructFrom($class, $values, $apiKey=null)
{
$obj = new $class(isset($values['id']) ? $values['id'] : null, $apiKey);
$obj->refreshFrom($values, $apiKey);
return $obj;
}
/**
* @param array $values
* @param string|null $apiKey
*
* @return Stripe_Object The object of the same class as $this constructed
* from the given values.
*/
public static function constructFrom($values, $apiKey=null)
{
return self::scopedConstructFrom(__CLASS__, $values, $apiKey);
}
/**
* Refreshes this object using the provided values.
*
* @param array $values
* @param string $apiKey
* @param boolean $partial Defaults to false.
*/
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) && isset($this[$k]))
continue;
if (self::$nestedUpdatableAttributes->includes($k) && is_array($v)) {
$this->_values[$k] = Stripe_Object::scopedConstructFrom(
'Stripe_AttachedObject', $v, $apiKey
);
} else {
$this->_values[$k] = Stripe_Util::convertToStripeObject($v, $apiKey);
}
$this->_transientValues->discard($k);
$this->_unsavedValues->discard($k);
}
}
/**
* @return array A recursive mapping of attributes to values for this object,
* including the proper value for deleted attributes.
*/
public function serializeParameters()
{
$params = array();
if ($this->_unsavedValues) {
foreach ($this->_unsavedValues->toArray() as $k) {
$v = $this->$k;
if ($v === NULL) {
$v = '';
}
$params[$k] = $v;
}
}
// Get nested updates.
foreach (self::$nestedUpdatableAttributes->toArray() as $property) {
if (isset($this->$property)
&& $this->$property instanceOf Stripe_Object) {
$params[$property] = $this->$property->serializeParameters();
}
}
return $params;
}
// Pretend to have late static bindings, even in PHP 5.2
protected function _lsb($method)
{
$class = get_class($this);
$args = array_slice(func_get_args(), 1);
return call_user_func_array(array($class, $method), $args);
}
protected static function _scopedLsb($class, $method)
{
$args = array_slice(func_get_args(), 2);
return call_user_func_array(array($class, $method), $args);
}
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()
{
$class = get_class($this);
return $class . ' JSON: ' . $this->__toJSON();
}
public function __toArray($recursive=false)
{
if ($recursive) {
return Stripe_Util::convertStripeObjectToArray($this->_values);
} else {
return $this->_values;
}
}
}
Stripe_Object::init();

View File

@ -0,0 +1,60 @@
<?php
class Stripe_Plan extends Stripe_ApiResource
{
/**
* @param string $id The ID of the plan to retrieve.
* @param string|null $apiKey
*
* @return Stripe_Plan
*/
public static function retrieve($id, $apiKey=null)
{
$class = get_class();
return self::_scopedRetrieve($class, $id, $apiKey);
}
/**
* @param array|null $params
* @param string|null $apiKey
*
* @return Stripe_Plan The created plan.
*/
public static function create($params=null, $apiKey=null)
{
$class = get_class();
return self::_scopedCreate($class, $params, $apiKey);
}
/**
* @param array|null $params
*
* @return Stripe_Plan The deleted plan.
*/
public function delete($params=null)
{
$class = get_class();
return self::_scopedDelete($class, $params);
}
/**
* @return Stripe_Plan The saved plan.
*/
public function save()
{
$class = get_class();
return self::_scopedSave($class);
}
/**
* @param array|null $params
* @param string|null $apiKey
*
* @return array An array of Stripe_Plans.
*/
public static function all($params=null, $apiKey=null)
{
$class = get_class();
return self::_scopedAll($class, $params, $apiKey);
}
}

View File

@ -0,0 +1,11 @@
<?php
class Stripe_RateLimitError extends Stripe_InvalidRequestError
{
public function __construct($message, $param, $httpStatus=null,
$httpBody=null, $jsonBody=null
)
{
parent::__construct($message, $httpStatus, $httpBody, $jsonBody);
}
}

View File

@ -0,0 +1,75 @@
<?php
class Stripe_Recipient extends Stripe_ApiResource
{
/**
* @param string $id The ID of the recipient to retrieve.
* @param string|null $apiKey
*
* @return Stripe_Recipient
*/
public static function retrieve($id, $apiKey=null)
{
$class = get_class();
return self::_scopedRetrieve($class, $id, $apiKey);
}
/**
* @param array|null $params
* @param string|null $apiKey
*
* @return array An array of Stripe_Recipients.
*/
public static function all($params=null, $apiKey=null)
{
$class = get_class();
return self::_scopedAll($class, $params, $apiKey);
}
/**
* @param array|null $params
* @param string|null $apiKey
*
* @return Stripe_Recipient The created recipient.
*/
public static function create($params=null, $apiKey=null)
{
$class = get_class();
return self::_scopedCreate($class, $params, $apiKey);
}
/**
* @return Stripe_Recipient The saved recipient.
*/
public function save()
{
$class = get_class();
return self::_scopedSave($class);
}
/**
* @param array|null $params
*
* @return Stripe_Recipient The deleted recipient.
*/
public function delete($params=null)
{
$class = get_class();
return self::_scopedDelete($class, $params);
}
/**
* @param array|null $params
*
* @return array An array of the recipient's Stripe_Transfers.
*/
public function transfers($params=null)
{
if (!$params)
$params = array();
$params['recipient'] = $this->id;
$transfers = Stripe_Transfer::all($params, $this->_apiKey);
return $transfers;
}
}

View File

@ -0,0 +1,36 @@
<?php
class Stripe_Refund extends Stripe_ApiResource
{
/**
* @return string The API URL for this Stripe refund.
*/
public function instanceUrl()
{
$id = $this['id'];
$charge = $this['charge'];
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);
$charge = Stripe_ApiRequestor::utf8($charge);
$base = self::classUrl('Stripe_Charge');
$chargeExtn = urlencode($charge);
$extn = urlencode($id);
return "$base/$chargeExtn/refunds/$extn";
}
/**
* @return Stripe_Refund The saved refund.
*/
public function save()
{
$class = get_class();
return self::_scopedSave($class);
}
}

View File

@ -0,0 +1,43 @@
<?php
class Stripe_RequestOptions
{
public $headers;
public $apiKey;
public function __construct($key, $headers)
{
$this->apiKey = $key;
$this->headers = $headers;
}
/**
* Unpacks an options array into an Options object
* @param array|string $options a key => value array
* @return Options
*/
public static function parse($options)
{
if (is_null($options)) {
return new Stripe_RequestOptions(null, array());
}
if (is_string($options)) {
return new Stripe_RequestOptions($options, array());
}
if (is_array($options)) {
$headers = array();
$key = null;
if (array_key_exists('api_key', $options)) {
$key = $options['api_key'];
}
if (array_key_exists('idempotency_key', $options)) {
$headers['Idempotency-Key'] = $options['idempotency_key'];
}
return new Stripe_RequestOptions($key, $headers);
}
throw new Stripe_Error("options must be a string, an array, or null");
}
}

View File

@ -0,0 +1,31 @@
<?php
abstract class Stripe_SingletonApiResource extends Stripe_ApiResource
{
protected static function _scopedSingletonRetrieve($class, $apiKey=null)
{
$instance = new $class(null, $apiKey);
$instance->refresh();
return $instance;
}
/**
* @param Stripe_SingletonApiResource $class
* @return string The endpoint associated with this singleton class.
*/
public static function classUrl($class)
{
$base = self::className($class);
return "/v1/${base}";
}
/**
* @return string The endpoint associated with this singleton API resource.
*/
public function instanceUrl()
{
$class = get_class($this);
$base = self::classUrl($class);
return "$base";
}
}

View File

@ -0,0 +1,77 @@
<?php
abstract class Stripe
{
/**
* @var string The Stripe API key to be used for requests.
*/
public static $apiKey;
/**
* @var string The base URL for the Stripe API.
*/
public static $apiBase = 'https://api.stripe.com';
/**
* @var string The base URL for the Stripe API uploads endpoint.
*/
public static $apiUploadBase = 'https://uploads.stripe.com';
/**
* @var string|null The version of the Stripe API to use for requests.
*/
public static $apiVersion = null;
/**
* @var boolean Defaults to true.
*/
public static $verifySslCerts = true;
const VERSION = '1.18.0';
/**
* @return string The API key used for requests.
*/
public static function getApiKey()
{
return self::$apiKey;
}
/**
* Sets the API key to be used for requests.
*
* @param string $apiKey
*/
public static function setApiKey($apiKey)
{
self::$apiKey = $apiKey;
}
/**
* @return string The API version used for requests. null if we're using the
* latest version.
*/
public static function getApiVersion()
{
return self::$apiVersion;
}
/**
* @param string $apiVersion The API version to use for requests.
*/
public static function setApiVersion($apiVersion)
{
self::$apiVersion = $apiVersion;
}
/**
* @return boolean
*/
public static function getVerifySslCerts()
{
return self::$verifySslCerts;
}
/**
* @param boolean $verify
*/
public static function setVerifySslCerts($verify)
{
self::$verifySslCerts = $verify;
}
}

View File

@ -0,0 +1,57 @@
<?php
class Stripe_Subscription extends Stripe_ApiResource
{
/**
* @return string The API URL for this Stripe subscription.
*/
public function instanceUrl()
{
$id = $this['id'];
$customer = $this['customer'];
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);
$customer = Stripe_ApiRequestor::utf8($customer);
$base = self::classUrl('Stripe_Customer');
$customerExtn = urlencode($customer);
$extn = urlencode($id);
return "$base/$customerExtn/subscriptions/$extn";
}
/**
* @param array|null $params
* @return Stripe_Subscription The deleted subscription.
*/
public function cancel($params=null)
{
$class = get_class();
return self::_scopedDelete($class, $params);
}
/**
* @return Stripe_Subscription The saved subscription.
*/
public function save()
{
$class = get_class();
return self::_scopedSave($class);
}
/**
* @return Stripe_Subscription The updated 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

@ -0,0 +1,28 @@
<?php
class Stripe_Token extends Stripe_ApiResource
{
/**
* @param string $id The ID of the token to retrieve.
* @param string|null $apiKey
*
* @return Stripe_Token
*/
public static function retrieve($id, $apiKey=null)
{
$class = get_class();
return self::_scopedRetrieve($class, $id, $apiKey);
}
/**
* @param array|null $params
* @param string|null $apiKey
*
* @return Stripe_Coupon The created token.
*/
public static function create($params=null, $apiKey=null)
{
$class = get_class();
return self::_scopedCreate($class, $params, $apiKey);
}
}

View File

@ -0,0 +1,62 @@
<?php
class Stripe_Transfer extends Stripe_ApiResource
{
/**
* @param string $id The ID of the transfer to retrieve.
* @param string|null $apiKey
*
* @return Stripe_Transfer
*/
public static function retrieve($id, $apiKey=null)
{
$class = get_class();
return self::_scopedRetrieve($class, $id, $apiKey);
}
/**
* @param array|null $params
* @param string|null $apiKey
*
* @return array An array of Stripe_Transfers.
*/
public static function all($params=null, $apiKey=null)
{
$class = get_class();
return self::_scopedAll($class, $params, $apiKey);
}
/**
* @param array|null $params
* @param string|null $apiKey
*
* @return Stripe_Transfer The created transfer.
*/
public static function create($params=null, $apiKey=null)
{
$class = get_class();
return self::_scopedCreate($class, $params, $apiKey);
}
/**
* @return Stripe_Transfer The canceled transfer.
*/
public function cancel()
{
$requestor = new Stripe_ApiRequestor($this->_apiKey);
$url = $this->instanceUrl() . '/cancel';
list($response, $apiKey) = $requestor->request('post', $url);
$this->refreshFrom($response, $apiKey);
return $this;
}
/**
* @return Stripe_Transfer The saved transfer.
*/
public function save()
{
$class = get_class();
return self::_scopedSave($class);
}
}

View File

@ -0,0 +1,94 @@
<?php
abstract class Stripe_Util
{
/**
* Whether the provided array (or other) is a list rather than a dictionary.
*
* @param array|mixed $array
* @return boolean True if the given object is a list.
*/
public static function isList($array)
{
if (!is_array($array))
return false;
// TODO: generally incorrect, but it's correct given Stripe's response
foreach (array_keys($array) as $k) {
if (!is_numeric($k))
return false;
}
return true;
}
/**
* Recursively converts the PHP Stripe object to an array.
*
* @param array $values The PHP Stripe object to convert.
* @return array
*/
public static function convertStripeObjectToArray($values)
{
$results = array();
foreach ($values as $k => $v) {
// FIXME: this is an encapsulation violation
if ($k[0] == '_') {
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;
}
/**
* Converts a response from the Stripe API to the corresponding PHP object.
*
* @param array $resp The response from the Stripe API.
* @param string $apiKey
* @return Stripe_Object|array
*/
public static function convertToStripeObject($resp, $apiKey)
{
$types = array(
'card' => 'Stripe_Card',
'charge' => 'Stripe_Charge',
'coupon' => 'Stripe_Coupon',
'customer' => 'Stripe_Customer',
'list' => 'Stripe_List',
'invoice' => 'Stripe_Invoice',
'invoiceitem' => 'Stripe_InvoiceItem',
'event' => 'Stripe_Event',
'transfer' => 'Stripe_Transfer',
'plan' => 'Stripe_Plan',
'recipient' => 'Stripe_Recipient',
'refund' => 'Stripe_Refund',
'subscription' => 'Stripe_Subscription',
'fee_refund' => 'Stripe_ApplicationFeeRefund',
'bitcoin_receiver' => 'Stripe_BitcoinReceiver',
'bitcoin_transaction' => 'Stripe_BitcoinTransaction'
);
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

@ -0,0 +1,39 @@
<?php
class Stripe_Util_Set implements IteratorAggregate
{
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]);
}
public function toArray()
{
return array_keys($this->_elts);
}
public function getIterator()
{
return new ArrayIterator($this->toArray());
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,57 @@
<?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";
$testURI = '/simpletest/autorun.php';
$ok = @include_once(dirname(__FILE__).$testURI);
if (!$ok) {
$ok = @include_once(dirname(__FILE__).'/../vendor/simpletest'.$testURI);
}
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
// @codingStandardsIgnoreStart
function exception_error_handler($errno, $errstr, $errfile, $errline)
{
throw new ErrorException($errstr, $errno, 0, $errfile, $errline);
}
// @codingStandardsIgnoreEnd
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/BalanceTest.php');
require_once(dirname(__FILE__) . '/Stripe/BalanceTransactionTest.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/SubscriptionTest.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/RefundTest.php');
require_once(dirname(__FILE__) . '/Stripe/ApplicationFeeTest.php');
require_once(dirname(__FILE__) . '/Stripe/ApplicationFeeRefundTest.php');
require_once(dirname(__FILE__) . '/Stripe/BitcoinReceiverTest.php');
require_once(dirname(__FILE__) . '/Stripe/UtilTest.php');
require_once(dirname(__FILE__) . '/Stripe/RequestOptionsTest.php');

View File

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

View File

@ -0,0 +1,124 @@
<?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);
$expected = 'my=value&that%5Byour%5D%5B%5D=cheese'
. '&that%5Byour%5D%5B%5D=whiz&bar=1';
$this->assertEqual($enc, $expected);
}
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"));
}
}
public function testBlacklistedPEMCert()
{
$cert =
// {{{ Revoked certificate from api.stripe.com
'-----BEGIN CERTIFICATE-----
MIIGoDCCBYigAwIBAgIQATGh1aL1Q3mXYwp7zTQ8+zANBgkqhkiG9w0BAQUFADBm
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSUwIwYDVQQDExxEaWdpQ2VydCBIaWdoIEFzc3VyYW5j
ZSBDQS0zMB4XDTEzMDkyNzAwMDAwMFoXDTE1MDEwODEyMDAwMFowajELMAkGA1UE
BhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBGcmFuY2lz
Y28xFTATBgNVBAoTDFN0cmlwZSwgSW5jLjEXMBUGA1UEAxMOYXBpLnN0cmlwZS5j
b20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC9a37/epvqPM/9ExSv
L4jOFyuT+h9+kSePtjRD4N2z/r9zqUt88TRe2TSPM0o7yqRAmggqck1iFQmmgkU8
i5YjaGBVUSp9jyWZ7U+G9L9IRmxxWoYKaofpnGiGuTnpWgPPYtooXx+mhatvmiiM
tdJCU5QCN4rSvH9QnMHGrGupSw0Hb68d5nbbfk5f3IdYpjFR0+b0RHIoSrYPhiJF
r3/4h61Iu3PFea70wASLnP0olKlstQ6FONpsoYBRONvgs8/gUPQVY/VllbEceEpt
Bm5fIP5Cgd+Zya9uGqXsru1MyPIrR93u/YHDSYpC1TJ+BlSAamoC8ahtRNXLueRM
OFn5AgMBAAGjggNEMIIDQDAfBgNVHSMEGDAWgBRQ6nOJ2yn7EI+e5QEg1N55mUiD
9zAdBgNVHQ4EFgQUVhDDlYPPyDwTr1hy5uUZYYHEJyYwGQYDVR0RBBIwEIIOYXBp
LnN0cmlwZS5jb20wDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMB
BggrBgEFBQcDAjBhBgNVHR8EWjBYMCqgKKAmhiRodHRwOi8vY3JsMy5kaWdpY2Vy
dC5jb20vY2EzLWcyNC5jcmwwKqAooCaGJGh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNv
bS9jYTMtZzI0LmNybDCCAcQGA1UdIASCAbswggG3MIIBswYJYIZIAYb9bAEBMIIB
pDA6BggrBgEFBQcCARYuaHR0cDovL3d3dy5kaWdpY2VydC5jb20vc3NsLWNwcy1y
ZXBvc2l0b3J5Lmh0bTCCAWQGCCsGAQUFBwICMIIBVh6CAVIAQQBuAHkAIAB1AHMA
ZQAgAG8AZgAgAHQAaABpAHMAIABDAGUAcgB0AGkAZgBpAGMAYQB0AGUAIABjAG8A
bgBzAHQAaQB0AHUAdABlAHMAIABhAGMAYwBlAHAAdABhAG4AYwBlACAAbwBmACAA
dABoAGUAIABEAGkAZwBpAEMAZQByAHQAIABDAFAALwBDAFAAUwAgAGEAbgBkACAA
dABoAGUAIABSAGUAbAB5AGkAbgBnACAAUABhAHIAdAB5ACAAQQBnAHIAZQBlAG0A
ZQBuAHQAIAB3AGgAaQBjAGgAIABsAGkAbQBpAHQAIABsAGkAYQBiAGkAbABpAHQA
eQAgAGEAbgBkACAAYQByAGUAIABpAG4AYwBvAHIAcABvAHIAYQB0AGUAZAAgAGgA
ZQByAGUAaQBuACAAYgB5ACAAcgBlAGYAZQByAGUAbgBjAGUALjB7BggrBgEFBQcB
AQRvMG0wJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBFBggr
BgEFBQcwAoY5aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0SGln
aEFzc3VyYW5jZUNBLTMuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQEFBQAD
ggEBAKPiwJIeR52VOjhPew9cx19nmkHXDxxPzcOmSsF3gk9jogXh61yA6DevcTBY
KTNUhkTRWujOUdwZqNuvaLCLwn/TEGV9hM4lOKah8yqCQB8PhT7baMiL7mltAhEE
SBs2soRGVXHr3AczRKLW3G+IbIpUc3vilOul/PXWHutfzz7/asxXSTk/siVKROQ8
/KWrujG6wopwEEGExhlYOYBuXObwoSCV2nqIgr92fpHGvbMIFKSICoT7RCm8EVcb
3PGuaL8B8TZVbTOPYoJHdPzeRxL8Rbg8sDogHR+jkqwwyhUCfuzVbOjWFJU1DKvr
CBoD8xKYd5r7CYf1Du+nNMmDmrE=
-----END CERTIFICATE-----';
// }}}
$this->assertTrue(Stripe_APIRequestor::isBlackListed($cert));
}
}

View File

@ -0,0 +1,16 @@
<?php
class Stripe_ApplicationFeeRefundTest extends StripeTestCase
{
public function testUrls()
{
$refund = new Stripe_ApplicationFeeRefund();
$refund->id = 'refund_id';
$refund->fee = 'fee_id';
$this->assertEqual(
$refund->instanceUrl(),
'/v1/application_fees/fee_id/refunds/refund_id'
);
}
}

View File

@ -0,0 +1,19 @@
<?php
class Stripe_ApplicationFeeTest extends StripeTestCase
{
public function testUrls()
{
$applicationFee = new Stripe_ApplicationFee('abcd/efgh');
$this->assertEqual(
$applicationFee->instanceUrl(), '/v1/application_fees/abcd%2Fefgh'
);
}
public function testList()
{
self::authorizeFromEnv();
$d = Stripe_ApplicationFee::all();
$this->assertEqual($d->url, '/v1/application_fees');
}
}

View File

@ -0,0 +1,14 @@
<?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

@ -0,0 +1,13 @@
<?php
class Stripe_BalanceTest extends StripeTestCase
{
public function testRetrieve()
{
self::authorizeFromEnv();
$d = Stripe_Balance::retrieve();
$this->assertEqual($d->object, "balance");
$this->assertTrue(Stripe_Util::isList($d->available));
$this->assertTrue(Stripe_Util::isList($d->pending));
}
}

View File

@ -0,0 +1,11 @@
<?php
class Stripe_BalanceTransactionTest extends StripeTestCase
{
public function testList()
{
self::authorizeFromEnv();
$d = Stripe_BalanceTransaction::all();
$this->assertEqual($d->url, '/v1/balance/history');
}
}

View File

@ -0,0 +1,56 @@
<?php
class Stripe_BitcoinReceiverTest extends StripeTestCase
{
public function testUrls()
{
$classUrl = Stripe_BitcoinReceiver::classUrl('Stripe_BitcoinReceiver');
$this->assertEqual($classUrl, '/v1/bitcoin/receivers');
$receiver = new Stripe_BitcoinReceiver('abcd/efgh');
$instanceUrl = $receiver->instanceUrl();
$this->assertEqual($instanceUrl, '/v1/bitcoin/receivers/abcd%2Fefgh');
}
public function testCreate()
{
self::authorizeFromEnv();
$receiver = $this->createTestBitcoinReceiver("do+fill_now@stripe.com");
$this->assertEqual(100, $receiver->amount);
$this->assertNotNull($receiver->id);
}
public function testRetrieve()
{
self::authorizeFromEnv();
$receiver = $this->createTestBitcoinReceiver("do+fill_now@stripe.com");
$r = Stripe_BitcoinReceiver::retrieve($receiver->id);
$this->assertEqual($receiver->id, $r->id);
$this->assertIsA($r->transactions->data[0], 'Stripe_BitcoinTransaction');
}
public function testList()
{
self::authorizeFromEnv();
$receiver = $this->createTestBitcoinReceiver("do+fill_now@stripe.com");
$receivers = Stripe_BitcoinReceiver::all();
$this->assertTrue(count($receivers->data) > 0);
}
public function testListTransactions()
{
self::authorizeFromEnv();
$receiver = $this->createTestBitcoinReceiver("do+fill_now@stripe.com");
$this->assertEqual(0, count($receiver->transactions->data));
$transactions = $receiver->transactions->all(array("limit" => 1));
$this->assertEqual(1, count($transactions->data));
}
}

View File

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

View File

@ -0,0 +1,200 @@
<?php
class Stripe_ChargeTest extends StripeTestCase
{
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()
{
self::authorizeFromEnv();
$card = array(
'number' => '4242424242424242',
'exp_month' => 5,
'exp_year' => 2015
);
$c = Stripe_Charge::create(
array(
'amount' => 100,
'currency' => 'usd',
'card' => $card
)
);
$this->assertTrue($c->paid);
$this->assertFalse($c->refunded);
}
public function testIdempotentCreate()
{
self::authorizeFromEnv();
$card = array(
'number' => '4242424242424242',
'exp_month' => 5,
'exp_year' => 2015
);
$c = Stripe_Charge::create(
array(
'amount' => 100,
'currency' => 'usd',
'card' => $card
),
array(
'idempotency_key' => $this->generateRandomString(),
)
);
$this->assertTrue($c->paid);
$this->assertFalse($c->refunded);
}
public function testRetrieve()
{
self::authorizeFromEnv();
$card = array(
'number' => '4242424242424242',
'exp_month' => 5,
'exp_year' => 2015
);
$c = Stripe_Charge::create(
array(
'amount' => 100,
'currency' => 'usd',
'card' => $card
)
);
$d = Stripe_Charge::retrieve($c->id);
$this->assertEqual($d->id, $c->id);
}
public function testUpdateMetadata()
{
self::authorizeFromEnv();
$card = array(
'number' => '4242424242424242',
'exp_month' => 5,
'exp_year' => 2015
);
$charge = Stripe_Charge::create(
array(
'amount' => 100,
'currency' => 'usd',
'card' => $card
)
);
$charge->metadata['test'] = 'foo bar';
$charge->save();
$updatedCharge = Stripe_Charge::retrieve($charge->id);
$this->assertEqual('foo bar', $updatedCharge->metadata['test']);
}
public function testUpdateMetadataAll()
{
self::authorizeFromEnv();
$card = array(
'number' => '4242424242424242',
'exp_month' => 5,
'exp_year' => 2015
);
$charge = Stripe_Charge::create(
array(
'amount' => 100,
'currency' => 'usd',
'card' => $card
)
);
$charge->metadata = array('test' => 'foo bar');
$charge->save();
$updatedCharge = Stripe_Charge::retrieve($charge->id);
$this->assertEqual('foo bar', $updatedCharge->metadata['test']);
}
public function testMarkAsFraudulent()
{
self::authorizeFromEnv();
$card = array(
'number' => '4242424242424242',
'exp_month' => 5,
'exp_year' => 2015
);
$charge = Stripe_Charge::create(
array(
'amount' => 100,
'currency' => 'usd',
'card' => $card
)
);
$charge->refunds->create();
$charge->markAsFraudulent();
$updatedCharge = Stripe_Charge::retrieve($charge->id);
$this->assertEqual(
'fraudulent', $updatedCharge['fraud_details']['user_report']
);
}
public function testCreateWithBitcoinReceiverSource()
{
self::authorizeFromEnv();
$receiver = $this->createTestBitcoinReceiver("do+fill_now@stripe.com");
$charge = Stripe_Charge::create(
array(
'amount' => 100,
'currency' => 'usd',
'source' => $receiver->id
)
);
$this->assertEqual($receiver->id, $charge->source->id);
$this->assertEqual("bitcoin_receiver", $charge->source->object);
$this->assertEqual("paid", $charge->status);
$this->assertTrue(get_class($charge->source) == 'Stripe_BitcoinReceiver');
}
public function markAsSafe()
{
self::authorizeFromEnv();
$card = array(
'number' => '4242424242424242',
'exp_month' => 5,
'exp_year' => 2015
);
$charge = Stripe_Charge::create(
array(
'amount' => 100,
'currency' => 'usd',
'card' => $card
)
);
$charge->markAsSafe();
$updatedCharge = Stripe_Charge::retrieve($charge->id);
$this->assertEqual('safe', $updatedCharge['fraud_details']['user_report']);
}
}

View File

@ -0,0 +1,27 @@
<?php
class Stripe_CouponTest extends StripeTestCase
{
public function testSave()
{
self::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);
// @codingStandardsIgnoreStart
$this->assertEqual(25, $c->percent_off);
// @codingStandardsIgnoreEnd
$c->metadata['foo'] = 'bar';
$c->save();
$stripeCoupon = Stripe_Coupon::retrieve($id);
$this->assertEqual($c->metadata, $stripeCoupon->metadata);
}
}

View File

@ -0,0 +1,211 @@
<?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');
$stripeCustomer = Stripe_Customer::retrieve($customer->id);
$this->assertEqual($customer->email, $stripeCustomer->email);
Stripe::setApiKey(null);
$customer = Stripe_Customer::create(null, StripeTestCase::API_KEY);
$customer->email = 'gdb@stripe.com';
$customer->save();
StripeTestCase::authorizeFromEnv();
$updatedCustomer = Stripe_Customer::retrieve($customer->id);
$this->assertEqual($updatedCustomer->email, 'gdb@stripe.com');
}
public function testBogusAttribute()
{
$customer = self::createTestCustomer();
$customer->bogus = 'bogus';
$this->expectException(new IsAExpectation('Stripe_InvalidRequestError'));
$customer->save();
}
public function testUpdateDescriptionEmpty()
{
$customer = self::createTestCustomer();
$this->expectException(new IsAExpectation('InvalidArgumentException'));
$customer->description = '';
}
public function testUpdateDescriptionNull()
{
$customer = self::createTestCustomer(array('description' => 'foo bar'));
$customer->description = NULL;
$customer->save();
$updatedCustomer = Stripe_Customer::retrieve($customer->id);
$this->assertEqual(NULL, $updatedCustomer->description);
}
public function testUpdateMetadata()
{
$customer = self::createTestCustomer();
$customer->metadata['test'] = 'foo bar';
$customer->save();
$updatedCustomer = Stripe_Customer::retrieve($customer->id);
$this->assertEqual('foo bar', $updatedCustomer->metadata['test']);
}
public function testDeleteMetadata()
{
$customer = self::createTestCustomer();
$customer->metadata = NULL;
$customer->save();
$updatedCustomer = Stripe_Customer::retrieve($customer->id);
$this->assertEqual(0, count($updatedCustomer->metadata->keys()));
}
public function testUpdateSomeMetadata()
{
$customer = self::createTestCustomer();
$customer->metadata['shoe size'] = '7';
$customer->metadata['shirt size'] = 'XS';
$customer->save();
$customer->metadata['shoe size'] = '9';
$customer->save();
$updatedCustomer = Stripe_Customer::retrieve($customer->id);
$this->assertEqual('XS', $updatedCustomer->metadata['shirt size']);
$this->assertEqual('9', $updatedCustomer->metadata['shoe size']);
}
public function testUpdateAllMetadata()
{
$customer = self::createTestCustomer();
$customer->metadata['shoe size'] = '7';
$customer->metadata['shirt size'] = 'XS';
$customer->save();
$customer->metadata = array('shirt size' => 'XL');
$customer->save();
$updatedCustomer = Stripe_Customer::retrieve($customer->id);
$this->assertEqual('XL', $updatedCustomer->metadata['shirt size']);
$this->assertFalse(isset($updatedCustomer->metadata['shoe size']));
}
public function testUpdateInvalidMetadata()
{
$customer = self::createTestCustomer();
$this->expectException(new IsAExpectation('Stripe_InvalidRequestError'));
$customer->metadata = 'something';
$customer->save();
}
public function testCancelSubscription()
{
$planID = 'gold-' . self::randomString();
self::retrieveOrCreatePlan($planID);
$customer = self::createTestCustomer(
array(
'plan' => $planID,
)
);
$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');
}
public function testCustomerAddCard()
{
$token = Stripe_Token::create(
array("card" => array(
"number" => "4242424242424242",
"exp_month" => 5,
"exp_year" => date('Y') + 3,
"cvc" => "314"
))
);
$customer = $this->createTestCustomer();
$createdCard = $customer->cards->create(array("card" => $token->id));
$customer->save();
$updatedCustomer = Stripe_Customer::retrieve($customer->id);
$updatedCards = $updatedCustomer->cards->all();
$this->assertEqual(count($updatedCards["data"]), 2);
}
public function testCustomerUpdateCard()
{
$customer = $this->createTestCustomer();
$customer->save();
$cards = $customer->cards->all();
$this->assertEqual(count($cards["data"]), 1);
$card = $cards['data'][0];
$card->name = "Jane Austen";
$card->save();
$updatedCustomer = Stripe_Customer::retrieve($customer->id);
$updatedCards = $updatedCustomer->cards->all();
$this->assertEqual($updatedCards["data"][0]->name, "Jane Austen");
}
public function testCustomerDeleteCard()
{
$token = Stripe_Token::create(
array("card" => array(
"number" => "4242424242424242",
"exp_month" => 5,
"exp_year" => date('Y') + 3,
"cvc" => "314"
))
);
$customer = $this->createTestCustomer();
$createdCard = $customer->cards->create(array("card" => $token->id));
$customer->save();
$updatedCustomer = Stripe_Customer::retrieve($customer->id);
$updatedCards = $updatedCustomer->cards->all();
$this->assertEqual(count($updatedCards["data"]), 2);
$deleteStatus =
$updatedCustomer->cards->retrieve($createdCard->id)->delete();
$this->assertEqual($deleteStatus->deleted, 1);
$updatedCustomer->save();
$postDeleteCustomer = Stripe_Customer::retrieve($customer->id);
$postDeleteCards = $postDeleteCustomer->cards->all();
$this->assertEqual(count($postDeleteCards["data"]), 1);
}
}

View File

@ -0,0 +1,29 @@
<?php
class Stripe_DiscountTest extends StripeTestCase
{
public function testDeletion()
{
self::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

@ -0,0 +1,22 @@
<?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());
}
}
}

View File

@ -0,0 +1,38 @@
<?php
class Stripe_FileUploadTest extends StripeTestCase
{
public function testCreateFile()
{
$fp = fopen(dirname(__FILE__).'/../data/test.png', 'r');
self::authorizeFromEnv();
$file = Stripe_FileUpload::create(
array(
'purpose' => 'dispute_evidence',
'file' => $fp,
)
);
fclose($fp);
$this->assertEqual(95, $file->size);
$this->assertEqual('image/png', $file->mimetype);
}
public function testCreateCurlFile()
{
if (!class_exists('CurlFile')) {
// Older PHP versions don't support this
return;
}
$file = new CurlFile(dirname(__FILE__).'/../data/test.png');
self::authorizeFromEnv();
$file = Stripe_FileUpload::create(
array(
'purpose' => 'dispute_evidence',
'file' => $file,
)
);
$this->assertEqual(95, $file->size);
$this->assertEqual('image/png', $file->mimetype);
}
}

View File

@ -0,0 +1,24 @@
<?php
class Stripe_InvalidRequestErrorTest extends StripeTestCase
{
public function testInvalidObject()
{
self::authorizeFromEnv();
try {
Stripe_Customer::retrieve('invalid');
} catch (Stripe_InvalidRequestError $e) {
$this->assertEqual(404, $e->getHttpStatus());
}
}
public function testBadData()
{
self::authorizeFromEnv();
try {
Stripe_Charge::create();
} catch (Stripe_InvalidRequestError $e) {
$this->assertEqual(400, $e->getHttpStatus());
}
}
}

View File

@ -0,0 +1,65 @@
<?php
class Stripe_InvoiceTest extends StripeTestCase
{
public function testUpcoming()
{
self::authorizeFromEnv();
$customer = self::createTestCustomer();
Stripe_InvoiceItem::create(
array(
'customer' => $customer->id,
'amount' => 0,
'currency' => 'usd',
)
);
$invoice = Stripe_Invoice::upcoming(
array(
'customer' => $customer->id,
)
);
$this->assertEqual($invoice->customer, $customer->id);
$this->assertEqual($invoice->attempted, false);
}
public function testItemsAccessWithParameter()
{
self::authorizeFromEnv();
$customer = self::createTestCustomer();
Stripe_InvoiceItem::create(
array(
'customer' => $customer->id,
'amount' => 100,
'currency' => 'usd',
)
);
$invoice = Stripe_Invoice::upcoming(
array(
'customer' => $customer->id,
)
);
$lines = $invoice->lines->all(
array(
'limit' => 10,
)
);
$this->assertEqual(count($lines->data), 1);
$this->assertEqual($lines->data[0]->amount, 100);
}
// This is really just making sure that this operation does not trigger any
// warnings, as it's highly nested.
public function testAll()
{
self::authorizeFromEnv();
$invoices = Stripe_Invoice::all();
$this->assertTrue(count($invoices) > 0);
}
}

View File

@ -0,0 +1,41 @@
<?php
class Stripe_ObjectTest extends UnitTestCase
{
public function testArrayAccessorsSemantics()
{
$s = new Stripe_Object();
$s['foo'] = 'a';
$this->assertEqual($s['foo'], 'a');
$this->assertTrue(isset($s['foo']));
unset($s['foo']);
$this->assertFalse(isset($s['foo']));
}
public function testNormalAccessorsSemantics()
{
$s = new Stripe_Object();
$s->foo = 'a';
$this->assertEqual($s->foo, 'a');
$this->assertTrue(isset($s->foo));
unset($s->foo);
$this->assertFalse(isset($s->foo));
}
public function testArrayAccessorsMatchNormalAccessors()
{
$s = new Stripe_Object();
$s->foo = 'a';
$this->assertEqual($s['foo'], 'a');
$s['bar'] = 'b';
$this->assertEqual($s->bar, 'b');
}
public function testKeys()
{
$s = new Stripe_Object();
$s->foo = 'a';
$this->assertEqual($s->keys(), array('foo'));
}
}

View File

@ -0,0 +1,53 @@
<?php
class Stripe_PlanTest extends StripeTestCase
{
public function testDeletion()
{
self::authorizeFromEnv();
$p = Stripe_Plan::create(
array(
'amount' => 2000,
'interval' => 'month',
'currency' => 'usd',
'name' => 'Plan',
'id' => 'gold-' . self::randomString()
)
);
$p->delete();
$this->assertTrue($p->deleted);
}
public function testFalseyId()
{
try {
$retrievedPlan = Stripe_Plan::retrieve('0');
} catch (Stripe_InvalidRequestError $e) {
// Can either succeed or 404, all other errors are bad
if ($e->httpStatus !== 404) {
$this->fail();
}
}
}
public function testSave()
{
self::authorizeFromEnv();
$planID = 'gold-' . self::randomString();
$p = Stripe_Plan::create(
array(
'amount' => 2000,
'interval' => 'month',
'currency' => 'usd',
'name' => 'Plan',
'id' => $planID
)
);
$p->name = 'A new plan name';
$p->save();
$this->assertEqual($p->name, 'A new plan name');
$stripePlan = Stripe_Plan::retrieve($planID);
$this->assertEqual($p->name, $stripePlan->name);
}
}

View File

@ -0,0 +1,116 @@
<?php
class Stripe_RecipientTest extends StripeTestCase
{
public function testDeletion()
{
$recipient = self::createTestRecipient();
$recipient->delete();
$this->assertTrue($recipient->deleted);
}
public function testSave()
{
$recipient = self::createTestRecipient();
$recipient->email = 'gdb@stripe.com';
$recipient->save();
$this->assertEqual($recipient->email, 'gdb@stripe.com');
$stripeRecipient = Stripe_Recipient::retrieve($recipient->id);
$this->assertEqual($recipient->email, $stripeRecipient->email);
}
public function testBogusAttribute()
{
$recipient = self::createTestRecipient();
$recipient->bogus = 'bogus';
$caught = null;
try {
$recipient->save();
} catch (Stripe_InvalidRequestError $exception) {
$caught = $exception;
}
$this->assertTrue($caught instanceof Stripe_InvalidRequestError);
}
public function testRecipientAddCard()
{
$token = Stripe_Token::create(
array("card" => array(
"number" => "4000056655665556",
"exp_month" => 5,
"exp_year" => date('Y') + 3,
"cvc" => "314"
))
);
$recipient = $this->createTestRecipient();
$createdCard = $recipient->cards->create(array("card" => $token->id));
$recipient->save();
$updatedRecipient = Stripe_Recipient::retrieve($recipient->id);
$updatedCards = $updatedRecipient->cards->all();
$this->assertEqual(count($updatedCards["data"]), 1);
}
public function testRecipientUpdateCard()
{
$token = Stripe_Token::create(
array("card" => array(
"number" => "4000056655665556",
"exp_month" => 5,
"exp_year" => date('Y') + 3,
"cvc" => "314"
))
);
$recipient = $this->createTestRecipient();
$createdCard = $recipient->cards->create(array("card" => $token->id));
$recipient->save();
$createdCards = $recipient->cards->all();
$this->assertEqual(count($createdCards["data"]), 1);
$card = $createdCards['data'][0];
$card->name = "Jane Austen";
$card->save();
$updatedRecipient = Stripe_Recipient::retrieve($recipient->id);
$updatedCards = $updatedRecipient->cards->all();
$this->assertEqual($updatedCards["data"][0]->name, "Jane Austen");
}
public function testRecipientDeleteCard()
{
$token = Stripe_Token::create(
array("card" => array(
"number" => "4000056655665556",
"exp_month" => 5,
"exp_year" => date('Y') + 3,
"cvc" => "314"
))
);
$recipient = $this->createTestRecipient();
$createdCard = $recipient->cards->create(array("card" => $token->id));
$recipient->save();
$updatedRecipient = Stripe_Recipient::retrieve($recipient->id);
$updatedCards = $updatedRecipient->cards->all();
$this->assertEqual(count($updatedCards["data"]), 1);
$deleteStatus =
$updatedRecipient->cards->retrieve($createdCard->id)->delete();
$this->assertEqual($deleteStatus->deleted, 1);
$updatedRecipient->save();
$postDeleteRecipient = Stripe_Recipient::retrieve($recipient->id);
$postDeleteCards = $postDeleteRecipient->cards->all();
$this->assertEqual(count($postDeleteCards["data"]), 0);
}
}

View File

@ -0,0 +1,61 @@
<?php
class Stripe_RefundTest extends StripeTestCase
{
public function testCreate()
{
$charge = self::createTestCharge();
$ref = $charge->refunds->create(array('amount' => 100));
$this->assertEqual(100, $ref->amount);
$this->assertEqual($charge->id, $ref->charge);
}
public function testUpdateAndRetrieve()
{
$charge = self::createTestCharge();
$ref = $charge->refunds->create(array('amount' => 100));
$ref->metadata["key"] = "value";
$ref->save();
$ref = $charge->refunds->retrieve($ref->id);
$this->assertEqual("value", $ref->metadata["key"], "value");
}
public function testList()
{
$charge = self::createTestCharge();
$refA = $charge->refunds->create(array('amount' => 50));
$refB = $charge->refunds->create(array('amount' => 50));
$all = $charge->refunds->all();
$this->assertEqual(false, $all['has_more']);
$this->assertEqual(2, count($all->data));
$this->assertEqual($refB->id, $all->data[0]->id);
$this->assertEqual($refA->id, $all->data[1]->id);
}
public function testCreateForBitcoin()
{
self::authorizeFromEnv();
$receiver = $this->createTestBitcoinReceiver("do+fill_now@stripe.com");
$charge = Stripe_Charge::create(
array(
"amount" => $receiver->amount,
"currency" => $receiver->currency,
"description" => $receiver->description,
'source' => $receiver->id
)
);
$ref = $charge->refunds->create(
array(
'amount' => $receiver->amount,
'refund_address' => 'ABCDEF'
)
);
$this->assertEqual($receiver->amount, $ref->amount);
$this->assertNotNull($ref->id);
}
}

View File

@ -0,0 +1,70 @@
<?php
class Stripe_RequestOptionsTest extends StripeTestCase
{
public function testStringAPIKey()
{
$opts = Stripe_RequestOptions::parse("foo");
$this->assertEqual("foo", $opts->apiKey);
$this->assertEqual(array(), $opts->headers);
}
public function testNull()
{
$opts = Stripe_RequestOptions::parse(null);
$this->assertEqual(null, $opts->apiKey);
$this->assertEqual(array(), $opts->headers);
}
public function testEmptyArray()
{
$opts = Stripe_RequestOptions::parse(array());
$this->assertEqual(null, $opts->apiKey);
$this->assertEqual(array(), $opts->headers);
}
public function testAPIKeyArray()
{
$opts = Stripe_RequestOptions::parse(
array(
'api_key' => 'foo',
)
);
$this->assertEqual('foo', $opts->apiKey);
$this->assertEqual(array(), $opts->headers);
}
public function testIdempotentKeyArray()
{
$opts = Stripe_RequestOptions::parse(
array(
'idempotency_key' => 'foo',
)
);
$this->assertEqual(null, $opts->apiKey);
$this->assertEqual(array('Idempotency-Key' => 'foo'), $opts->headers);
}
public function testKeyArray()
{
$opts = Stripe_RequestOptions::parse(
array(
'idempotency_key' => 'foo',
'api_key' => 'foo'
)
);
$this->assertEqual('foo', $opts->apiKey);
$this->assertEqual(array('Idempotency-Key' => 'foo'), $opts->headers);
}
public function testWrongType()
{
$caught = false;
try {
$opts = Stripe_RequestOptions::parse(5);
} catch (Stripe_Error $e) {
$caught = true;
}
$this->assertTrue($caught);
}
}

View File

@ -0,0 +1,60 @@
<?php
class Stripe_SubscriptionTest extends StripeTestCase
{
public function testCreateUpdateCancel()
{
$planID = 'gold-' . self::randomString();
self::retrieveOrCreatePlan($planID);
$customer = self::createTestCustomer();
$sub = $customer->subscriptions->create(array('plan' => $planID));
$this->assertEqual($sub->status, 'active');
$this->assertEqual($sub->plan->id, $planID);
$sub->quantity = 2;
$sub->save();
$sub = $customer->subscriptions->retrieve($sub->id);
$this->assertEqual($sub->status, 'active');
$this->assertEqual($sub->plan->id, $planID);
$this->assertEqual($sub->quantity, 2);
$sub->cancel(array('at_period_end' => true));
$sub = $customer->subscriptions->retrieve($sub->id);
$this->assertEqual($sub->status, 'active');
// @codingStandardsIgnoreStart
$this->assertTrue($sub->cancel_at_period_end);
// @codingStandardsIgnoreEnd
}
public function testDeleteDiscount()
{
$planID = 'gold-' . self::randomString();
self::retrieveOrCreatePlan($planID);
$couponID = '25off-' . self::randomString();
self::retrieveOrCreateCoupon($couponID);
$customer = self::createTestCustomer();
$sub = $customer->subscriptions->create(
array(
'plan' => $planID,
'coupon' => $couponID
)
);
$this->assertEqual($sub->status, 'active');
$this->assertEqual($sub->plan->id, $planID);
$this->assertEqual($sub->discount->coupon->id, $couponID);
$sub->deleteDiscount();
$sub = $customer->subscriptions->retrieve($sub->id);
$this->assertNull($sub->discount);
}
}

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