Skip to content

Instantly share code, notes, and snippets.

@antonlukin
Last active June 3, 2021 13:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save antonlukin/9347142e08ef725227fca08b8047823b to your computer and use it in GitHub Desktop.
Save antonlukin/9347142e08ef725227fca08b8047823b to your computer and use it in GitHub Desktop.
Upload canvas poster and display custom sharing urls.
<html>
<head>
<meta charset="utf-8">
<title>Canvas saver</title>
</head>
<body>
<canvas id="canvas" width="600" height="315"></canvas>
<p>
<button id="button">Сохранить постер</button>
</p>
<p id="content"></p>
<script>
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
context.fillStyle = "#ddd";
context.fillRect(0, 0, canvas.width, canvas.height);
// begin custom shape
context.beginPath();
context.moveTo(170, 80);
context.bezierCurveTo(130, 100, 130, 150, 230, 150);
context.bezierCurveTo(250, 180, 320, 180, 340, 150);
context.bezierCurveTo(420, 150, 420, 120, 390, 100);
context.bezierCurveTo(430, 40, 370, 30, 340, 50);
context.bezierCurveTo(320, 5, 250, 20, 250, 50);
context.bezierCurveTo(200, 5, 150, 20, 170, 80);
// complete custom shape
context.closePath();
context.lineWidth = 5;
context.fillStyle = '#8ED6FF';
context.fill();
context.strokeStyle = 'blue';
context.stroke();
var button = document.getElementById('button');
var result = document.getElementById('result');
button.addEventListener('click', function(e) {
e.preventDefault();
button.textContent = 'Загрузка...';
content.innerHTML = '';
var formData = new FormData();
formData.append('poster', canvas.toDataURL());
var request = new XMLHttpRequest();
request.open( 'POST', '/share/upload/' );
request.responseType = 'json';
request.addEventListener('readystatechange', function() {
if (request.readyState === 4) {
button.textContent = 'Сохранить постер';
}
});
request.addEventListener('load', function() {
var response = request.response || {};
if (!response.success) {
return alert('error');
}
var link = document.createElement('a');
link.href = response.data.link;
link.textContent = response.data.link;
link.target = '_blank';
content.appendChild(link);
var image = document.createElement('img');
image.src = response.data.poster;
image.style.display = 'block';
image.style.marginTop = '20px';
content.appendChild(image);
});
request.addEventListener('error', function() {
alert('error');
});
request.send(formData);
});
</script>
</body>
</html>
<?php
namespace Tigers\Dvor;
/**
* Upload and save canvas posters to show them as sharing results.
*
* @author Anton Lukin
* @version 1.0
* @license MIT License
*/
final class Sharing
{
/**
* Url to project home page.
*/
public $url = 'https://example.org';
/**
* Redirect page to desired location;
*
* @param string $location New page location.
* @param int $status HTTP header status. By default: 301.
*/
private function redirect_page($location, $status = 301) {
header("Location: {$location}", true, $status);
exit;
}
/**
* Generate unique poster name.
*/
private function get_unique_name() {
return sha1(uniqid('', true));
}
/**
* Decode base64 image from POST request.
*
* @param string $image Base64 encoded png image.
*/
private function decode_image($image) {
return base64_decode(str_replace('data:image/png;base64,', '', $image));
}
/**
* Send JSON and exit.
*
* @param int $status HTTP status code.
* @param array $output Data to response.
*/
private function send_json($output, $status) {
http_response_code($status);
header('Content-Type: application/json');
echo json_encode($output);
exit;
}
/**
* Send JSON width error message.
*
* @param mixed $data Error data.
* @param int $status HTTP status code. By default: 500.
*/
private function send_json_error($data, $status = 500) {
$output = array(
'success' => false,
'data' => $data,
);
return $this->send_json($output, $status);
}
/**
* Send JSON with success message.
*
* @param mixed $data Success data.
* @param int $status HTTP status code. By default: 500.
*/
private function send_json_success($data) {
$output = array(
'success' => true,
'data' => $data,
);
return $this->send_json($output, 200);
}
/**
* Upload poster from js FormData.
*/
private function upload_poster() {
if (empty($_POST['poster'])) {
$this->send_json_error('The poster field should be defined', 400);
}
$image = $this->decode_image($_POST['poster']);
if (false === $image) {
$this->send_json_error('Wrong base64 image format', 400);
}
$name = $this->get_unique_name();
// Try to save poster.
$file = file_put_contents(__DIR__ . "/posters/{$name}.png", $image);
if (false === $file) {
$this->send_json_error('Failed to save poster');
}
$data = array(
'link' => $this->url . "/share/{$name}/",
'poster' => $this->url . "/share/posters/{$name}.png",
);
$this->send_json_success($data);
}
/**
* Show tags template.
*
* @param string $name Poster name.
*/
private function show_tags($name) {
if (!file_exists(__DIR__ . "/posters/{$name}.png")) {
$this->redirect_page($this->url);
}
$meta = array(
'poster' => $this->url . "/share/posters/{$name}.png",
'title' => 'Я собрал этот отличный конструктор, собери и ты',
'description' => 'Тут более подробное описание',
);
extract( $meta );
include_once __DIR__ . '/templates/page.php';
}
/**
* Routing an incoming request.
*
* @param string $action Request control parameter.
*/
private function route_request($action) {
if ('upload' === $action) {
return $this->upload_poster();
}
$this->show_tags($action);
}
/**
* Start with server request uri.
*
* @param string $request Request URI.
*/
public function init($request) {
$args = explode('/', trim($request, '/'));
if (empty($args[1])) {
$this->redirect_page($this->url);
}
$this->route_request($args[1]);
}
}
(new Sharing)->init($_SERVER['REQUEST_URI']);
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="title" content="<?= $title; ?>">
<meta name="description" content="<?= $description; ?>">
<meta property="og:title" content="<?= $title; ?>">
<meta property="og:description" content="<?= $description; ?>">
<meta property="og:image" content="<?= $poster ?>">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:image" content="<?= $poster ?>">
<title><?php echo $title; ?></title>
</head>
<body>
<script type="text/javascript">
window.location.href = '<?php echo $this->url; ?>';
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment