Skip to content

Commit 2867f45

Browse files
gabidavilabshaffer
authored andcommitted
Cloud SQL connection using PDO PostgreSQL (GoogleCloudPlatform#766)
* Code sample connecting PostgreSQL on Cloud SQL * Added validation for vote * Updated Readme and added appengine template file * Fixing env variable name * Fixed the DSN for PDO for PostgreSQL * Correct Link for AppEngine PHP 7.2 * Renaming files and fixing code style * Renaming folder * Moved logic from controller to index.php * FIxes identation * Moved example to inside PDO folder * Added information about appengine entrypoint
1 parent 1fe802a commit 2867f45

File tree

7 files changed

+372
-0
lines changed

7 files changed

+372
-0
lines changed

cloud_sql/postgres/pdo/README.md

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# Connection to Cloud SQL - PostgreSQL
2+
3+
## Before you begin
4+
5+
1. Before you use this code sample, you need to have [Composer](https://getcomposer.org/) installed or downloaded into this folder. Download instructions can be found [here](https://getcomposer.org/download/).
6+
2. Create a PostgreSQL Cloud SQL Instance by following these [instructions](https://cloud.google.com/sql/docs/postgres/create-instance). Note the connection string, database user, and database password that you create.
7+
3. Create a database for your application by following these [instructions](https://cloud.google.com/sql/docs/postgres/create-manage-databases). Note the database name.
8+
4. Create a service account with the 'Cloud SQL Client' permissions by following these [instructions](https://cloud.google.com/sql/docs/postgres/connect-external-app#4_if_required_by_your_authentication_method_create_a_service_account). Download a JSON key to use to authenticate your connection.
9+
5. Use the information noted in the previous steps:
10+
11+
```bash
12+
export GOOGLE_APPLICATION_CREDENTIALS=/path/to/service/account/key.json
13+
export CLOUD_SQL_CONNECTION_NAME='::'
14+
export DB_USER='my-db-user'
15+
export DB_PASS='my-db-pass'
16+
export DB_NAME='my-db-name'
17+
export DB_HOSTNAME='localhost' # If connecting using cloud_sql_proxy
18+
```
19+
20+
Note: Saving credentials in environment variables is convenient, but not secure - consider a more secure solution such as [Cloud KMS](https://cloud.google.com/kms/) to help keep secrets safe.
21+
22+
## Running Locally
23+
24+
To run this application locally, download and install the `cloud_sql_proxy` by following the instructions [here](https://cloud.google.com/sql/docs/postgres/sql-proxy#install).
25+
26+
Once the proxy is ready, use the following command to start the proxy in the background:
27+
28+
```bash
29+
$ ./cloud_sql_proxy -dir=/cloudsql --instances=$CLOUD_SQL_CONNECTION_NAME --credential_file=$GOOGLE_APPLICATION_CREDENTIALS
30+
```
31+
32+
Note: Make sure to run the command under a user with write access in the `/cloudsql` directory. This proxy will use this folder to create a unix socket the application will use to connect to Cloud SQL.
33+
34+
Next, install the dependencies using Composer:
35+
36+
```bash
37+
$ composer install
38+
```
39+
OR
40+
41+
```bash
42+
$ php composer.phar install
43+
```
44+
45+
Execute the following:
46+
47+
```bash
48+
$ php -S localhost:8080 index.php
49+
```
50+
51+
Navigate towards http://localhost:8080 to verify your application is running correctly.
52+
53+
## Google App Engine Standard
54+
55+
To run on GAE-Standard, create an App Engine project by following the setup for these [instructions](https://cloud.google.com/appengine/docs/standard/php7/quickstart#before-you-begin).
56+
57+
First, update `app.yaml` with the correct values to pass the environment variables into the runtime.
58+
59+
Next, the following command will deploy the application to your Google Cloud project:
60+
61+
```bash
62+
$ gcloud app deploy
63+
```
64+

cloud_sql/postgres/pdo/app.yaml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Copyright 2018 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
runtime: php72
16+
17+
# Remember - storing secrets in plaintext is potentially unsafe. Consider using
18+
# something like https://cloud.google.com/kms/ to help keep secrets secret.
19+
env_variables:
20+
CLOUD_SQL_INSTANCE_NAME: ::
21+
DB_USER: my-db-user
22+
DB_PASS: my-db-pass
23+
DB_NAME: my_db
24+
25+
# Defaults to "serve index.php" and "serve public/index.php". Can be used to
26+
# serve a custom PHP front controller (e.g. "serve backend/index.php") or to
27+
# run a long-running PHP script as a worker process (e.g. "php worker.php").
28+
#
29+
# entrypoint: serve index.php

cloud_sql/postgres/pdo/composer.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"autoload": {
3+
"psr-4": {
4+
"Google\\Cloud\\Samples\\CloudSQL\\Postgres\\": "src/"
5+
}
6+
}
7+
}

cloud_sql/postgres/pdo/index.php

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
2+
# Copyright 2018 Google LLC
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
16+
require 'vendor/autoload.php';
17+
18+
use Google\Cloud\Samples\CloudSQL\Postgres\DB;
19+
use Google\Cloud\Samples\CloudSQL\Postgres\Votes;
20+
21+
$votes = new Votes(new DB());
22+
23+
if ($_SERVER['REQUEST_URI'] == '/' && $_SERVER['REQUEST_METHOD'] == 'GET') {
24+
$list = $votes->list();
25+
26+
$vote_count = $votes->count_candidates();
27+
$tab_count = $vote_count['tabs'];
28+
$space_count = $vote_count['spaces'];
29+
30+
include_once("./template.php");
31+
32+
} elseif ($_SERVER['REQUEST_URI'] == '/' && $_SERVER['REQUEST_METHOD'] == 'POST') {
33+
$message = 'Invalid vote. Choose Between TABS and SPACES';
34+
35+
if (!empty($_POST['team']) && in_array($_POST['team'], ['SPACES', 'TABS'])) {
36+
$message = $votes->save($_POST['team']);
37+
}
38+
39+
echo $message;
40+
}

cloud_sql/postgres/pdo/src/DB.php

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
2+
# Copyright 2018 Google LLC
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
16+
namespace Google\Cloud\Samples\CloudSQL\Postgres;
17+
18+
use PDO;
19+
20+
class DB
21+
{
22+
private $connection;
23+
24+
public function __construct()
25+
{
26+
$config = [
27+
"username" => getenv("DB_USER"),
28+
"password" => getenv("DB_PASS"),
29+
"schema" => getenv("DB_NAME"),
30+
"hostname" => getenv("DB_HOSTNAME") ?: "127.0.0.1",
31+
"cloud_sql_instance_name" => getenv("CLOUD_SQL_INSTANCE_NAME")
32+
];
33+
34+
$this->connection = $this->connect($config);
35+
}
36+
37+
private function connect($config)
38+
{
39+
$dsn = "pgsql:dbname={$config['schema']};host={$config['hostname']}";
40+
41+
if ($config["cloud_sql_instance_name"] != "") {
42+
$dsn = "pgsql:dbname={$config['schema']};host=/cloudsql/{$config['cloud_sql_instance_name']}";
43+
}
44+
45+
return new PDO($dsn, $config['username'], $config['password']);
46+
}
47+
48+
public function get_connection()
49+
{
50+
return $this->connection;
51+
}
52+
}

cloud_sql/postgres/pdo/src/Votes.php

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
2+
# Copyright 2018 Google LLC
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
16+
namespace Google\Cloud\Samples\CloudSQL\Postgres;
17+
18+
use Google\Cloud\Samples\CloudSQL\Postgres\DB;
19+
20+
class Votes
21+
{
22+
private $connection;
23+
24+
public function __construct(DB $db)
25+
{
26+
$this->connection = $db->get_connection();
27+
$this->create_table();
28+
}
29+
30+
private function create_table()
31+
{
32+
$sql = "
33+
CREATE TABLE IF NOT EXISTS votes (
34+
vote_id SERIAL NOT NULL,
35+
time_cast TIMESTAMP NOT NULL,
36+
candidate VARCHAR(6) NOT NULL,
37+
PRIMARY KEY (vote_id)
38+
);";
39+
$this->connection->exec($sql);
40+
}
41+
42+
public function list()
43+
{
44+
$sql = "SELECT candidate, time_cast FROM votes ORDER BY time_cast DESC LIMIT 5";
45+
$statement = $this->connection->prepare($sql);
46+
$statement->execute();
47+
48+
return $statement->fetchAll();
49+
}
50+
51+
public function count_candidates()
52+
{
53+
$sql = "SELECT COUNT(vote_id) FROM votes WHERE candidate = ?";
54+
$count = [];
55+
56+
$statement = $this->connection->prepare($sql);
57+
58+
//tabs
59+
$statement->execute(['TABS']);
60+
$count['tabs'] = $statement->fetch()['count'];
61+
62+
//spaces
63+
$statement->execute(['SPACES']);
64+
$count['spaces'] = $statement->fetch()['count'];
65+
66+
return $count;
67+
}
68+
69+
public function save($team)
70+
{
71+
$sql = "INSERT INTO votes (time_cast, candidate) VALUES ('NOW()', :candidate)";
72+
$statement = $this->connection->prepare($sql);
73+
$statement->bindParam('candidate', $team);
74+
75+
if ($statement->execute()) {
76+
return "Vote successfully cast for '$team'";
77+
}
78+
79+
return $this->connection->errorInfo();
80+
}
81+
}

cloud_sql/postgres/pdo/template.php

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
16+
17+
18+
Tabs VS Spaces
19+
20+
href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css">
21+
22+
23+
24+
25+
26+
27+
28+
29+
30+
31+
32+

33+
if ($tab_count == $space_count): ?>
34+
TABS and SPACES are evenly matched!
35+
elseif ($tab_count > $space_count): ?>
36+
TABS are winning by $tab_count - $space_count?>
37+
$tab_count - $space_count > 1 ? "votes" : "vote" ?>!
38+
elseif ($space_count > $tab_count): ?>
39+
SPACES are winning by $space_count - $tab_count?>
40+
$space_count - $tab_count > 1 ? "votes" : "vote" ?>!
41+
endif ?>
42+
43+
44+
45+
46+
$tab_count > $space_count ?: 'green lighten-3' ?>">
47+
keyboard_tab
48+

$tab_count?> votes

49+
50+
51+
52+
53+
$tab_count < $space_count ?: 'blue lighten-3' ?>">
54+
space_bar
55+

$space_count?> votes

56+
57+
58+
59+
60+

Recent Votes

61+
    62+
    foreach($list as $vote): ?>
    63+
  • 64+
    if ($vote['candidate'] == "TABS"): ?>
    65+
    keyboard_tab
    66+
    elseif ($vote['candidate'] == "SPACES"): ?>
    67+
    space_bar
    68+
    endif ?>
    69+
    70+
    A vote for $vote['candidate'] ?>
    71+
    72+

    was cast at $vote['time_cast'] ?>

    73+
    74+
    endforeach ?>
    75+
    76+
    77+
    98+
    99+

    0 commit comments

    Comments
     (0)