Hướng dẫn dùng postgres notify trong PHP

I have a problem or misunderstanding with Postgre trigger -> perform notify -> capture into PHP flow.

My Platform is PHP(5.6) in centos with Postgres.

I have to add trigger with notifications table and whenever a new notification is added to that notifications SMS has to send to that user.

So here added trigger like this

CREATE FUNCTION xxx_sms_trigger() RETURNS trigger LANGUAGE plpgsql AS $$ DECLARE BEGIN PERFORM pg_notify('sms', NEW.id||'' ); RETURN new; END;

and in php the inserting new notifications work fine.

Now I have a separate file where added this capturing pg_notify triggering by "pg_get_notify", here I couldn't get this flow totally like how Postgres can trigger some unknown php script without its being running as service or how I can make it work?

Hướng dẫn dùng postgres notify trong PHP

asked May 9, 2014 at 18:49

ElamuruganElamurugan

3,16413 gold badges58 silver badges103 bronze badges

5

You do need a php script running as a service. If that is going to be the language that receives the notification you provide. As @FelipeRosa says, that script will need to connect to the database, then issue at least one command:

listen sms;

There is a good example of the listen on the main site (http://www.php.net/manual/en/function.pg-get-notify.php)

I haven't coded in php in a few years. Recently I have implemented this logic in python, but it should be about the same. I did a little research, and I can find select() in php, but it seems that the postgres socket descriptor is not available in php, so you can't use the select() in php unless you can find the postgres socket descriptor.

Anyway, that thread is here (http://postgresql.1045698.n5.nabble.com/Is-there-any-way-to-listen-to-NOTIFY-in-php-without-polling-td5749888.html). There is a polling example in there for your php script side down near the bottom. You can do the listen as previous selected (once), then put your pg_get_notify() in a loop with a sleep in there for the amount of time you are willing to queue notifications.

Just fwiw, in python I don't poll, I select.select(pg_conn,...), when data arrives on the postgres connection I check it for notifications, so there is no 'polling'. It would be nice if you could find a way to use select() in php instead of looping.

-g

answered May 9, 2014 at 20:09

Hướng dẫn dùng postgres notify trong PHP

Here’s a cohesive example that registers an interest in a table insertion, waits for notification (or timeout) and responds to the caller. We use a timestamp preceded by the letter ‘C’ to identify the notification channel since Postgres requires the channel name to be a proper identifier.

Postgres SQL

/* We want to know when items of interest get added to this table. Asynchronous insertions possible from different process or server */ DROP TABLE IF EXISTS History; CREATE TABLE History ( HistoryId INT PRIMARY KEY, MYKEY CHAR(17), Description TEXT, TimeStamp BIGINT ); /* Table of registered interest in a notification */ DROP TABLE IF EXISTS Notifications; CREATE TABLE Notifications ( NotificationId INT PRIMARY KEY, Channel VARCHAR(20), MYKEY CHAR(17) ); /* Function to process a single insertion to History table */ CREATE OR REPLACE FUNCTION notify_me() RETURNS trigger AS $BODY$ DECLARE ch varchar(20); BEGIN FOR ch IN SELECT DISTINCT Channel FROM Notifications WHERE MYKEY=NEW.MYKEY LOOP /* NOTIFY ch, 'from notify_me trigger'; */ EXECUTE 'NOTIFY C' || ch || ', ' || quote_literal('from notify_me') || ';'; DELETE FROM Notifications WHERE Channel=ch; END LOOP; RETURN NULL; END; $BODY$ LANGUAGE 'plpgsql'; /* Trigger to process all insertions to History table */ DROP TRIGGER IF EXISTS HistNotify ON History CASCADE; CREATE TRIGGER HistNotify AFTER INSERT ON History FOR EACH ROW EXECUTE PROCEDURE notify_me();

PHP code

// $conn is a PDO connection handle to the Postgres DB // $MYKEY is a key field of interest $TimeStamp = time(); // UNIX time (seconds since 1970) of the request $timeout = 120; // Maximum seconds before responding // Register our interest in new history log activity $rg = $conn->prepare("INSERT INTO Notifications (MYKEY, Channel) VALUES (?,?)"); $rg->execute(array($MYKEY, $TimeStamp)); // Wait until something to report $conn->exec('LISTEN C'.$TimeStamp.';'); // Prepend ‘C’ to get notification channel $conn->exec('COMMIT;'); // Postgres may need this to start listening $conn->pgsqlGetNotify (PDO::FETCH_ASSOC, $timeout*1000); // Convert from sec to ms // Unregister our interest $st = $conn->prepare("DELETE FROM Notifications WHERE Channel=?"); $st->execute(array($TimeStamp));

answered Nov 19, 2015 at 22:55

Hướng dẫn dùng postgres notify trong PHP

SteveSteve

311 bronze badge

Here is an example how to migrate the "Python way" mentioned by @Greg to PHP. After starting the script below - open a new connection to the postgres db and query NOTIFY "test", 'I am the payload'

Sources:

  • http://initd.org/psycopg/docs/advanced.html#asynchronous-notifications
  • https://gist.github.com/chernomyrdin/96812377f1ac5bf567b8

<?php $dsn = 'user=postgres dbname=postgres password=postgres port=5432 host=localhost'; $connection = \pg_connect($dsn); if (\pg_connection_status($connection) === \PGSQL_CONNECTION_BAD) { throw new \Exception( sprintf('The database connect failed: %s', \pg_last_error($connection)) ); } \pg_query('LISTEN "test"'); while (true) { $read = [\pg_socket($connection)]; $write = null; $except = null; $num = \stream_select( $read, $write, $except, 60 ); if ($num === false) { throw new \Exception('Error in optaining the stream resource'); } if (\pg_connection_status($connection) !== \PGSQL_CONNECTION_OK) { throw new \Exception('pg_connection_status() is not PGSQL_CONNECTION_OK'); } elseif ($num) { $notify = \pg_get_notify($connection); if ($notify !== false) { var_dump($notify); } } }

answered Dec 17, 2017 at 14:21

madflowmadflow

6,9342 gold badges34 silver badges49 bronze badges

According to this you should first make the application listen to the desired channel issuing the command "LISTEN ", via pg_query for example, before you can notify messages to the application.

answered May 9, 2014 at 19:06

Hướng dẫn dùng postgres notify trong PHP

Its a litte example:

The PHP script (I named it teste.php - It's the same at http://php.net/manual/pt_BR/function.pg-get-notify.php):

$conn = pg_pconnect("dbname=mydb"); if (!$conn) { echo "An error occurred.\n"; exit; } while(true){ pg_query($conn, 'LISTEN SMS;'); $notify = pg_get_notify($conn); if (!$notify) { echo "No messages\n"; // change it as u want } else { print_r($notify); //your code here } sleep(2); }

Keep the script runnig (I assumed u are using linux):

php teste.php > log.txt 2>&1 &

Note that:

2>&1 redirects both standard output and standard error into the log.txt file.

& runs the whole thing in the background

You can follow the log.txt with this command:

tail -f log.txt

answered Apr 5, 2017 at 13:40

Hướng dẫn dùng postgres notify trong PHP

Not the answer you're looking for? Browse other questions tagged postgresql plpgsql database-trigger or ask your own question.