{"id":1382,"date":"2026-09-25T07:00:00","date_gmt":"2026-09-25T05:00:00","guid":{"rendered":"https:\/\/programaraciegas.net\/?p=1382"},"modified":"2026-09-15T06:01:00","modified_gmt":"2026-09-15T04:01:00","slug":"como-enviar-notificaciones-a-slack-desde-php-macos-y-windows","status":"publish","type":"post","link":"https:\/\/programaraciegas.net\/?p=1382","title":{"rendered":"C\u00f3mo enviar notificaciones a Slack desde PHP, macOS y Windows"},"content":{"rendered":"<p>En la actualidad trabajamos con m\u00e1quinas que realizan procesos largos<br \/>\no, incluso, esas m\u00e1quinas est\u00e1n lejos de nosotros. Cuando sucede alg\u00fan<br \/>\nevento que nos interese, como que ha terminado de procesar un fichero<br \/>\ngrande o nuestro sitio web est\u00e1 recibiendo un ataque, recibir una<br \/>\nnotificaci\u00f3n de este hecho podr\u00eda ayudarnos a ser m\u00e1s proactivos y vivir<br \/>\nm\u00e1s tranquilos.<\/p>\n<p>Construir un sistema de notificaciones puede ser una tarea enorme e,<br \/>\nincluso, cara econ\u00f3micamente. Pero existen alternativas ya<br \/>\nconstruidas.<\/p>\n<p>Una forma sencilla de construir nuestro propio sistema de<br \/>\nnotificaciones consiste en utilizar <strong>Slack<\/strong> y su posibilidad de crear aplicaciones o <strong>bots<\/strong>.<\/p>\n<p>La ventaja es que nuestros programas no necesitan conocer c\u00f3mo<br \/>\nfunciona el sistema de notificaciones de Windows, MacOS, Android o iOS.<br \/>\nSolamente tienen que enviar un mensaje a Slack.<\/p>\n<h2 id=\"qu\u00e9-es-slack\">\u00bfQu\u00e9 es Slack?<\/h2>\n<p><a href=\"https:\/\/slack.com\/\">Slack<\/a> es una plataforma de comunicaci\u00f3n basada principalmente en mensajes organizados mediante espacios de trabajo, canales y conversaciones.<\/p>\n<p>Slack est\u00e1 principalmente orientada a equipos de trabajo pero tambi\u00e9n<br \/>\npuede resultar \u00fatil como herramienta personal. Slack dispone de<br \/>\naplicaciones para diferentes sistemas operativos y dispositivos m\u00f3viles,<br \/>\npor lo que un mensaje enviado a nuestro espacio de trabajo puede<br \/>\nconvertirse inmediatamente en una notificaci\u00f3n en nuestro ordenador,<br \/>\ntel\u00e9fono m\u00f3vil o smartWatch, dependiendo de c\u00f3mo tengamos configuradas<br \/>\nlas notificaciones.<\/p>\n<p>Esta caracter\u00edstica permite utilizar Slack como intermediario entre<br \/>\nnuestros programas y nuestros dispositivos.<\/p>\n<h2 id=\"aprender-creando\">Aprender creando<\/h2>\n<p>La mejor forma de aprender algo es haciendo algo pr\u00e1ctico. Vamos a<br \/>\ncrear la infraestructura necesaria para enviar desde nuestro PC con<br \/>\nWindows, nuestro Macbook con MacOS o nuestro hosting web con PHP un<br \/>\nmensaje a Slack para que nos llegue a todos nuestros dispositivos<br \/>\nconectados a Slack.<\/p>\n<p>T\u00e9cnicamente haremos esto: nuestro programa detectar\u00e1 un determinado<br \/>\nacontecimiento y realizar\u00e1 una petici\u00f3n HTTPS a la API de Slack. Slack<br \/>\nrecibir\u00e1 el mensaje y se encargar\u00e1 de distribuirlo a nuestros<br \/>\ndispositivos conectados.<\/p>\n<p>Esto permite crear multitud de automatizaciones. Por ejemplo:<\/p>\n<ul>\n<li>avisarnos cuando finaliza una copia de seguridad;<\/li>\n<li>recibir una alerta cuando se produce un error en nuestra p\u00e1gina<br \/>\nweb;<\/li>\n<li>conocer cu\u00e1ndo termina una tarea programada;<\/li>\n<li>avisarnos si queda poco espacio disponible en un servidor;<\/li>\n<li>recibir el resultado de un proceso ejecutado mediante<br \/>\n<code>cron<\/code>;<\/li>\n<li>saber cu\u00e1ndo termina una conversi\u00f3n de v\u00eddeo que tarda varias<br \/>\nhoras;<\/li>\n<li>recibir una alerta cuando un determinado servicio deja de<br \/>\nfuncionar;<\/li>\n<li>conocer cu\u00e1ndo ha finalizado un proceso en nuestro Mac;<\/li>\n<li>o recibir desde Windows el resultado de un script de<br \/>\nmantenimiento.<\/li>\n<\/ul>\n<h3 id=\"slack-gratuito-y-el-l\u00edmite-de-aplicaciones\">Slack gratuito y el<br \/>\nl\u00edmite de aplicaciones<\/h3>\n<p>Para realizar este tutorial podemos utilizar un espacio de trabajo<br \/>\ngratuito de Slack.<\/p>\n<p>Conviene distinguir entre una <strong>aplicaci\u00f3n<\/strong> y un <strong>bot<\/strong>. En este art\u00edculo crearemos una aplicaci\u00f3n personalizada de Slack y dentro de ella utilizaremos un usuario bot para enviar los mensajes.<\/p>\n<p>En el plan gratuito existen l\u00edmites sobre las aplicaciones e<br \/>\nintegraciones que podemos instalar. Por ejemplo, actualmente Slack<br \/>\nestablece un l\u00edmite de <strong>10 aplicaciones de terceros o<br \/>\naplicaciones personalizadas instaladas<\/strong> en un espacio de trabajo gratuito.<\/p>\n<p>Podemos crear una \u00fanica aplicaci\u00f3n, por ejemplo, llamada<br \/>\n<strong>Notificaciones<\/strong> y utilizar la misma aplicaci\u00f3n para enviar notificaciones desde nuestro MacBook, nuestro PC y nuestro hosting web. Incluso podemos crear diferentes canales y desde el programa elegir d\u00f3nde publicar.<\/p>\n<p>Con este enfoque una \u00fanica aplicaci\u00f3n de Slack puede centralizar las<br \/>\nnotificaciones procedentes de muchos sistemas diferentes.<\/p>\n<h3 id=\"crear-nuestra-aplicaci\u00f3n-en-slack\">Crear nuestra aplicaci\u00f3n en<br \/>\nSlack<\/h3>\n<p>El primer paso consiste en crear una aplicaci\u00f3n de Slack.<\/p>\n<p>Debemos acceder a la web de <a href=\"https:\/\/api.slack.com\/apps\">la<br \/>\nAPI de Slack<\/a> y crear una nueva aplicaci\u00f3n.<\/p>\n<p>Podemos darle un nombre descriptivo como<br \/>\n<strong>Notificaciones<\/strong>.<\/p>\n<p>Tambi\u00e9n tendremos que indicar el espacio de trabajo de Slack en el<br \/>\nque queremos instalarla.<\/p>\n<p>Una aplicaci\u00f3n de Slack puede disponer de diferentes permisos. Como<br \/>\nen nuestro caso \u00fanicamente queremos publicar mensajes, debemos conceder<br \/>\nal bot el permiso OAuth <em>chat:write<\/em>. Este permiso permite que la aplicaci\u00f3n publique mensajes.<\/p>\n<p>Despu\u00e9s instalaremos la aplicaci\u00f3n en nuestro espacio de trabajo.<br \/>\nDurante el proceso, Slack generar\u00e1 un <strong>Bot User OAuth<br \/>\nToken<\/strong>.<\/p>\n<p>Los tokens de bot suelen comenzar por <code>xoxb-<\/code>, por ejemplo:<\/p>\n<pre class=\"text\"><code>xoxb-XXXXXXXXXXXX-XXXXXXXXXXXX-XXXXXXXXXXXXXXXXXXXXXXXX<\/code><\/pre>\n<p>Este token es una <strong>credencial secreta<\/strong>.<\/p>\n<p>No debemos publicarlo en una p\u00e1gina web, subirlo a un repositorio<br \/>\np\u00fablico ni incluirlo en un ejemplo que vayamos a compartir con otras<br \/>\npersonas.<\/p>\n<p>Cualquier persona que consiga un token v\u00e1lido podr\u00eda utilizar los<br \/>\npermisos asociados a nuestra aplicaci\u00f3n.<\/p>\n<p>Si accidentalmente hacemos p\u00fablico el token, debemos revocarlo y<br \/>\ngenerar unas credenciales nuevas.<\/p>\n<h3 id=\"a\u00f1adir-el-bot-al-canal\">A\u00f1adir el bot al canal<\/h3>\n<p>Tambi\u00e9n necesitaremos un lugar en el que publicar las<br \/>\nnotificaciones.<\/p>\n<p>Podemos crear, por ejemplo, un canal llamado<br \/>\n<strong>#notificaciones<\/strong>.<\/p>\n<p>Una vez hecho esto necesitaremos conocer el identificador del<br \/>\ncanal.<\/p>\n<p>Los identificadores de canales de Slack tienen un aspecto similar a<br \/>\n<code>C0123456789<\/code>. Este identificador ser\u00e1 el que utilizaremos al llamar a la API.<\/p>\n<p>Slack permite otras formas de organizar y enviar mensajes, pero para<br \/>\nun sistema personal de alertas un canal espec\u00edfico suele ser el enfoque<br \/>\napropiado.<\/p>\n<h3 id=\"c\u00f3mo-se-env\u00eda-un-mensaje-a-slack\">C\u00f3mo se env\u00eda un mensaje a<br \/>\nSlack<\/h3>\n<p>Slack proporciona el m\u00e9todo de su API<br \/>\n<strong>chat.postMessage<\/strong>.<\/p>\n<p>La petici\u00f3n se realiza mediante HTTPS utilizando la URL<br \/>\n<em>https:\/\/slack.com\/api\/chat.postMessage<\/em>.<\/p>\n<p>Debemos enviar nuestro token mediante la cabecera HTTP:<\/p>\n<pre class=\"text\"><code>Authorization: Bearer TOKEN<\/code><\/pre>\n<p>y proporcionar como m\u00ednimo el canal y el contenido del mensaje.<\/p>\n<p>Conceptualmente enviaremos un documento JSON parecido a este:<\/p>\n<div id=\"cb3\" class=\"sourceCode\">\n<pre class=\"sourceCode json\"><code class=\"sourceCode json\"><span id=\"cb3-1\"><span class=\"fu\">{<\/span><\/span>\n<span id=\"cb3-2\">    <span class=\"dt\">\"channel\"<\/span><span class=\"fu\">:<\/span> <span class=\"st\">\"C0123456789\"<\/span><span class=\"fu\">,<\/span><\/span>\n<span id=\"cb3-3\">    <span class=\"dt\">\"text\"<\/span><span class=\"fu\">:<\/span> <span class=\"st\">\"Copia de seguridad terminada correctamente\"<\/span><\/span>\n<span id=\"cb3-4\"><span class=\"fu\">}<\/span><\/span><\/code><\/pre>\n<\/div>\n<p>Esta operaci\u00f3n es independiente del lenguaje de programaci\u00f3n que<br \/>\nutilicemos.<\/p>\n<p>Por esta raz\u00f3n podemos realizar exactamente la misma petici\u00f3n desde<br \/>\nPHP, AppleScript, PowerShell, Python, Java, C# o pr\u00e1cticamente cualquier<br \/>\nentorno capaz de efectuar una petici\u00f3n HTTPS.<\/p>\n<p>Vamos a ver tres ejemplos.<\/p>\n<h4 id=\"enviar-una-notificaci\u00f3n-a-slack-desde-php\">Enviar una<br \/>\nnotificaci\u00f3n a Slack desde PHP<\/h4>\n<p>Supongamos que tenemos una p\u00e1gina web alojada en un hosting PHP y<br \/>\nqueremos recibir una notificaci\u00f3n cuando sucede alg\u00fan<br \/>\nacontecimiento.<\/p>\n<p>Podr\u00eda tratarse de una tarea ejecutada mediante <code>cron<\/code>, una copia de seguridad o un proceso interno de nuestra aplicaci\u00f3n.<\/p>\n<p>Una implementaci\u00f3n sencilla utilizando cURL ser\u00eda la siguiente:<\/p>\n<div id=\"cb4\" class=\"sourceCode\">\n<pre class=\"sourceCode php\"><code class=\"sourceCode php\"><span id=\"cb4-1\"><span class=\"kw\">&lt;?php<\/span><\/span>\n<span id=\"cb4-2\"><\/span>\n<span id=\"cb4-3\"><span class=\"va\">$token<\/span> <span class=\"op\">=<\/span> <span class=\"fu\">getenv<\/span>(<span class=\"st\">'SLACK_BOT_TOKEN'<\/span>)<span class=\"ot\">;<\/span><\/span>\n<span id=\"cb4-4\"><span class=\"va\">$canal<\/span> <span class=\"op\">=<\/span> <span class=\"st\">'C0123456789'<\/span><span class=\"ot\">;<\/span><\/span>\n<span id=\"cb4-5\"><\/span>\n<span id=\"cb4-6\"><span class=\"va\">$datos<\/span> <span class=\"op\">=<\/span> [<\/span>\n<span id=\"cb4-7\">    <span class=\"st\">'channel'<\/span> =&gt; <span class=\"va\">$canal<\/span><span class=\"ot\">,<\/span><\/span>\n<span id=\"cb4-8\">    <span class=\"st\">'text'<\/span> =&gt; <span class=\"st\">'Mensaje enviado desde mi servidor PHP'<\/span><\/span>\n<span id=\"cb4-9\">]<span class=\"ot\">;<\/span><\/span>\n<span id=\"cb4-10\"><\/span>\n<span id=\"cb4-11\"><span class=\"va\">$curl<\/span> <span class=\"op\">=<\/span> <span class=\"fu\">curl_init<\/span>(<span class=\"st\">'https:\/\/slack.com\/api\/chat.postMessage'<\/span>)<span class=\"ot\">;<\/span><\/span>\n<span id=\"cb4-12\"><\/span>\n<span id=\"cb4-13\"><span class=\"fu\">curl_setopt_array<\/span>(<span class=\"va\">$curl<\/span><span class=\"ot\">,<\/span> [<\/span>\n<span id=\"cb4-14\">    <span class=\"cn\">CURLOPT_POST<\/span> =&gt; <span class=\"kw\">true<\/span><span class=\"ot\">,<\/span><\/span>\n<span id=\"cb4-15\">    <span class=\"cn\">CURLOPT_RETURNTRANSFER<\/span> =&gt; <span class=\"kw\">true<\/span><span class=\"ot\">,<\/span><\/span>\n<span id=\"cb4-16\">    <span class=\"cn\">CURLOPT_HTTPHEADER<\/span> =&gt; [<\/span>\n<span id=\"cb4-17\">        <span class=\"st\">'Authorization: Bearer '<\/span> <span class=\"op\">.<\/span> <span class=\"va\">$token<\/span><span class=\"ot\">,<\/span><\/span>\n<span id=\"cb4-18\">        <span class=\"st\">'Content-Type: application\/json; charset=utf-8'<\/span><\/span>\n<span id=\"cb4-19\">    ]<span class=\"ot\">,<\/span><\/span>\n<span id=\"cb4-20\">    <span class=\"cn\">CURLOPT_POSTFIELDS<\/span> =&gt; <span class=\"fu\">json_encode<\/span>(<span class=\"va\">$datos<\/span>)<\/span>\n<span id=\"cb4-21\">])<span class=\"ot\">;<\/span><\/span>\n<span id=\"cb4-22\"><\/span>\n<span id=\"cb4-23\"><span class=\"va\">$respuesta<\/span> <span class=\"op\">=<\/span> <span class=\"fu\">curl_exec<\/span>(<span class=\"va\">$curl<\/span>)<span class=\"ot\">;<\/span><\/span>\n<span id=\"cb4-24\"><\/span>\n<span id=\"cb4-25\"><span class=\"fu\">curl_close<\/span>(<span class=\"va\">$curl<\/span>)<span class=\"ot\">;<\/span><\/span>\n<span id=\"cb4-26\"><\/span>\n<span id=\"cb4-27\"><span class=\"kw\">echo<\/span> <span class=\"va\">$respuesta<\/span><span class=\"ot\">;<\/span><\/span><\/code><\/pre>\n<\/div>\n<p>El token se obtiene mediante:<\/p>\n<div id=\"cb5\" class=\"sourceCode\">\n<pre class=\"sourceCode php\"><code class=\"sourceCode php\"><span id=\"cb5-1\"><span class=\"fu\">getenv<\/span>(<span class=\"st\">'SLACK_BOT_TOKEN'<\/span>)<\/span><\/code><\/pre>\n<\/div>\n<p>en lugar de escribirlo directamente en el c\u00f3digo.<\/p>\n<p>Siempre que nuestro hosting lo permita, resulta preferible almacenar<br \/>\ncredenciales y secretos mediante variables de entorno o mediante alg\u00fan<br \/>\nmecanismo de configuraci\u00f3n situado fuera del directorio p\u00fablico de<br \/>\nnuestra p\u00e1gina web.<\/p>\n<h5 id=\"crear-una-funci\u00f3n-php-para-enviar-mensajes\">Crear una funci\u00f3n<br \/>\nPHP para enviar mensajes<\/h5>\n<p>Si vamos a utilizar Slack desde diferentes partes de nuestra<br \/>\naplicaci\u00f3n PHP, podemos encapsular el c\u00f3digo anterior en una<br \/>\nfunci\u00f3n:<\/p>\n<div id=\"cb6\" class=\"sourceCode\">\n<pre class=\"sourceCode php\"><code class=\"sourceCode php\"><span id=\"cb6-1\"><span class=\"kw\">function<\/span> enviarSlack(<span class=\"va\">$mensaje<\/span>)<\/span>\n<span id=\"cb6-2\">{<\/span>\n<span id=\"cb6-3\">    <span class=\"va\">$token<\/span> <span class=\"op\">=<\/span> <span class=\"fu\">getenv<\/span>(<span class=\"st\">'SLACK_BOT_TOKEN'<\/span>)<span class=\"ot\">;<\/span><\/span>\n<span id=\"cb6-4\">    <span class=\"va\">$canal<\/span> <span class=\"op\">=<\/span> <span class=\"st\">'C0123456789'<\/span><span class=\"ot\">;<\/span><\/span>\n<span id=\"cb6-5\"><\/span>\n<span id=\"cb6-6\">    <span class=\"va\">$datos<\/span> <span class=\"op\">=<\/span> [<\/span>\n<span id=\"cb6-7\">        <span class=\"st\">'channel'<\/span> =&gt; <span class=\"va\">$canal<\/span><span class=\"ot\">,<\/span><\/span>\n<span id=\"cb6-8\">        <span class=\"st\">'text'<\/span> =&gt; <span class=\"va\">$mensaje<\/span><\/span>\n<span id=\"cb6-9\">    ]<span class=\"ot\">;<\/span><\/span>\n<span id=\"cb6-10\"><\/span>\n<span id=\"cb6-11\">    <span class=\"va\">$curl<\/span> <span class=\"op\">=<\/span> <span class=\"fu\">curl_init<\/span>(<span class=\"st\">'https:\/\/slack.com\/api\/chat.postMessage'<\/span>)<span class=\"ot\">;<\/span><\/span>\n<span id=\"cb6-12\"><\/span>\n<span id=\"cb6-13\">    <span class=\"fu\">curl_setopt_array<\/span>(<span class=\"va\">$curl<\/span><span class=\"ot\">,<\/span> [<\/span>\n<span id=\"cb6-14\">        <span class=\"cn\">CURLOPT_POST<\/span> =&gt; <span class=\"kw\">true<\/span><span class=\"ot\">,<\/span><\/span>\n<span id=\"cb6-15\">        <span class=\"cn\">CURLOPT_RETURNTRANSFER<\/span> =&gt; <span class=\"kw\">true<\/span><span class=\"ot\">,<\/span><\/span>\n<span id=\"cb6-16\">        <span class=\"cn\">CURLOPT_HTTPHEADER<\/span> =&gt; [<\/span>\n<span id=\"cb6-17\">            <span class=\"st\">'Authorization: Bearer '<\/span> <span class=\"op\">.<\/span> <span class=\"va\">$token<\/span><span class=\"ot\">,<\/span><\/span>\n<span id=\"cb6-18\">            <span class=\"st\">'Content-Type: application\/json; charset=utf-8'<\/span><\/span>\n<span id=\"cb6-19\">        ]<span class=\"ot\">,<\/span><\/span>\n<span id=\"cb6-20\">        <span class=\"cn\">CURLOPT_POSTFIELDS<\/span> =&gt; <span class=\"fu\">json_encode<\/span>(<span class=\"va\">$datos<\/span>)<\/span>\n<span id=\"cb6-21\">    ])<span class=\"ot\">;<\/span><\/span>\n<span id=\"cb6-22\"><\/span>\n<span id=\"cb6-23\">    <span class=\"va\">$respuesta<\/span> <span class=\"op\">=<\/span> <span class=\"fu\">curl_exec<\/span>(<span class=\"va\">$curl<\/span>)<span class=\"ot\">;<\/span><\/span>\n<span id=\"cb6-24\"><\/span>\n<span id=\"cb6-25\">    <span class=\"fu\">curl_close<\/span>(<span class=\"va\">$curl<\/span>)<span class=\"ot\">;<\/span><\/span>\n<span id=\"cb6-26\"><\/span>\n<span id=\"cb6-27\">    <span class=\"cf\">return<\/span> <span class=\"va\">$respuesta<\/span><span class=\"ot\">;<\/span><\/span>\n<span id=\"cb6-28\">}<\/span><\/code><\/pre>\n<\/div>\n<p>Ahora podemos enviar una notificaci\u00f3n simplemente escribiendo:<\/p>\n<div id=\"cb7\" class=\"sourceCode\">\n<pre class=\"sourceCode php\"><code class=\"sourceCode php\"><span id=\"cb7-1\">enviarSlack(<span class=\"st\">'La copia de seguridad ha terminado correctamente.'<\/span>)<span class=\"ot\">;<\/span><\/span><\/code><\/pre>\n<\/div>\n<p>Para enviar una notificaci\u00f3n de que se ha terminado la copia de<br \/>\nseguridad ser\u00eda algo como:<\/p>\n<div id=\"cb8\" class=\"sourceCode\">\n<pre class=\"sourceCode php\"><code class=\"sourceCode php\"><span id=\"cb8-1\"><span class=\"cf\">if<\/span> (<span class=\"va\">$copiaCorrecta<\/span>) {<\/span>\n<span id=\"cb8-2\">    enviarSlack(<span class=\"st\">'&#x2705; Copia de seguridad terminada correctamente.'<\/span>)<span class=\"ot\">;<\/span><\/span>\n<span id=\"cb8-3\">} <span class=\"cf\">else<\/span> {<\/span>\n<span id=\"cb8-4\">    enviarSlack(<span class=\"st\">'&#x26a0;&#xfe0f; Se ha producido un error durante la copia de seguridad.'<\/span>)<span class=\"ot\">;<\/span><\/span>\n<span id=\"cb8-5\">}<\/span><\/code><\/pre>\n<\/div>\n<p>Podemos incluir en el mensaje cualquier informaci\u00f3n que resulte<br \/>\n\u00fatil:<\/p>\n<div id=\"cb9\" class=\"sourceCode\">\n<pre class=\"sourceCode php\"><code class=\"sourceCode php\"><span id=\"cb9-1\">enviarSlack(<\/span>\n<span id=\"cb9-2\">    <span class=\"st\">\"Nuevo pedido recibido.<\/span><span class=\"sc\">\\n<\/span><span class=\"st\">\"<\/span> <span class=\"op\">.<\/span><\/span>\n<span id=\"cb9-3\">    <span class=\"st\">\"N\u00famero: \"<\/span> <span class=\"op\">.<\/span> <span class=\"va\">$pedido<\/span> <span class=\"op\">.<\/span> <span class=\"st\">\"<\/span><span class=\"sc\">\\n<\/span><span class=\"st\">\"<\/span> <span class=\"op\">.<\/span><\/span>\n<span id=\"cb9-4\">    <span class=\"st\">\"Importe: \"<\/span> <span class=\"op\">.<\/span> <span class=\"va\">$importe<\/span> <span class=\"op\">.<\/span> <span class=\"st\">\" euros\"<\/span><\/span>\n<span id=\"cb9-5\">)<span class=\"ot\">;<\/span><\/span><\/code><\/pre>\n<\/div>\n<p>De esta manera, un acontecimiento producido en nuestro hosting puede<br \/>\ngenerar inmediatamente una notificaci\u00f3n en nuestro tel\u00e9fono.<\/p>\n<h4 id=\"enviar-una-notificaci\u00f3n-desde-un-mac-con-applescript\">Enviar una<br \/>\nnotificaci\u00f3n desde un Mac con AppleScript<\/h4>\n<p>El mismo sistema puede utilizarse desde macOS.<\/p>\n<p>AppleScript no necesita disponer de una implementaci\u00f3n espec\u00edfica de<br \/>\nla API de Slack. Podemos utilizar el comando <code>curl<\/code> incluido en macOS mediante <code>do shell script<\/code>.<\/p>\n<p>Un ejemplo ser\u00eda:<\/p>\n<pre class=\"applescript\"><code>set slackToken to \"xoxb-XXXXXXXXXXXX\"\nset slackChannel to \"C0123456789\"\nset slackMessage to \"El proceso del Mac ha terminado correctamente\"\n\nset jsonData to \"{\\\"channel\\\":\\\"\" &amp; slackChannel &amp; \"\\\",\\\"text\\\":\\\"\" &amp; slackMessage &amp; \"\\\"}\"\n\nset command to \"curl -s -X POST \" &amp; \u00ac\n    \"-H \" &amp; quoted form of (\"Authorization: Bearer \" &amp; slackToken) &amp; \" \" &amp; \u00ac\n    \"-H \" &amp; quoted form of \"Content-Type: application\/json; charset=utf-8\" &amp; \" \" &amp; \u00ac\n    \"--data \" &amp; quoted form of jsonData &amp; \" \" &amp; \u00ac\n    quoted form of \"https:\/\/slack.com\/api\/chat.postMessage\"\n\ndo shell script command<\/code><\/pre>\n<p>En un script real debemos evitar almacenar el token directamente en<br \/>\nel c\u00f3digo cuando exista la posibilidad de que ese archivo pueda ser<br \/>\ncompartido.<\/p>\n<p>Una posibilidad es guardarlo en una variable de entorno, un archivo<br \/>\nde configuraci\u00f3n protegido o utilizar el llavero de macOS.<\/p>\n<h5 id=\"avisarnos-cuando-termina-un-proceso-en-el-mac\">Avisarnos cuando<br \/>\ntermina un proceso en el Mac<\/h5>\n<p>Supongamos que utilizamos nuestro Mac para ejecutar una tarea que<br \/>\ntarda mucho tiempo.<\/p>\n<p>Nuestro AppleScript podr\u00eda realizar primero el proceso:<\/p>\n<pre class=\"applescript\"><code>do shell script \"\/ruta\/a\/mi\/programa\"<\/code><\/pre>\n<p>y despu\u00e9s enviar el mensaje a Slack:<\/p>\n<pre class=\"applescript\"><code>set slackMessage to \"El proceso ha terminado.\"<\/code><\/pre>\n<p>De esta manera podemos abandonar el ordenador y recibir una<br \/>\nnotificaci\u00f3n en el tel\u00e9fono cuando la tarea haya finalizado.<\/p>\n<p>Tambi\u00e9n podr\u00edamos utilizar el resultado del proceso para enviar<br \/>\nmensajes diferentes dependiendo de si la operaci\u00f3n ha terminado<br \/>\ncorrectamente o se ha producido alg\u00fan error.<\/p>\n<h4 id=\"enviar-una-notificaci\u00f3n-desde-windows-con-un-archivo-bat\">Enviar<br \/>\nuna notificaci\u00f3n desde Windows con un archivo BAT<\/h4>\n<p>Windows tambi\u00e9n puede participar en nuestro sistema de<br \/>\nnotificaciones.<\/p>\n<p>Podemos utilizar PowerShell para realizar la petici\u00f3n HTTP e<br \/>\ninvocarlo desde un archivo <code>.bat<\/code>.<\/p>\n<p>Por ejemplo, podemos crear un archivo llamado<br \/>\n<strong>notificar.bat<\/strong> con el siguiente contenido:<\/p>\n<div id=\"cb13\" class=\"sourceCode\">\n<pre class=\"sourceCode bat\"><code class=\"sourceCode dosbat\"><span id=\"cb13-1\"><span class=\"kw\">@<\/span><span class=\"bu\">echo off<\/span><\/span>\n<span id=\"cb13-2\"><\/span>\n<span id=\"cb13-3\"><span class=\"bu\">set<\/span> <span class=\"st\">\"<\/span><span class=\"va\">SLACK_TOKEN<\/span>=<span class=\"st\">xoxb-XXXXXXXXXXXX\"<\/span><\/span>\n<span id=\"cb13-4\"><span class=\"bu\">set<\/span> <span class=\"st\">\"<\/span><span class=\"va\">SLACK_CHANNEL<\/span>=<span class=\"st\">C0123456789\"<\/span><\/span>\n<span id=\"cb13-5\"><span class=\"bu\">set<\/span> <span class=\"st\">\"<\/span><span class=\"va\">SLACK_MESSAGE<\/span>=<span class=\"st\">El proceso de Windows ha terminado\"<\/span><\/span>\n<span id=\"cb13-6\"><\/span>\n<span id=\"cb13-7\">powershell <span class=\"at\">-NoProfile<\/span> <span class=\"at\">-Command<\/span> ^<\/span>\n<span id=\"cb13-8\">  <span class=\"st\">\"$headers = @{ Authorization = 'Bearer <\/span><span class=\"pp\">%<\/span><span class=\"va\">SLACK_TOKEN<\/span><span class=\"pp\">%<\/span><span class=\"st\">' }; ^<\/span><\/span>\n<span id=\"cb13-9\">   $body = @{ channel = '<span class=\"pp\">%<\/span><span class=\"va\">SLACK_CHANNEL<\/span><span class=\"pp\">%<\/span>'; text = '<span class=\"pp\">%<\/span><span class=\"va\">SLACK_MESSAGE<\/span><span class=\"pp\">%<\/span>' } <span class=\"kw\">|<\/span> ConvertTo-Json; ^<\/span>\n<span id=\"cb13-10\">   Invoke-RestMethod <span class=\"at\">-Uri<\/span> 'https:\/<span class=\"at\">\/slack<\/span>.com<span class=\"at\">\/api\/chat<\/span>.postMessage' <span class=\"at\">-Method<\/span> Post <span class=\"at\">-Headers<\/span> $headers <span class=\"at\">-ContentType<\/span> 'application<span class=\"at\">\/json<\/span>; charset=utf<span class=\"at\">-8<\/span>' <span class=\"at\">-Body<\/span> $body<span class=\"st\">\"<\/span><\/span><\/code><\/pre>\n<\/div>\n<h5 id=\"ejecutar-la-notificaci\u00f3n-despu\u00e9s-de-otro-programa\">Ejecutar la<br \/>\nnotificaci\u00f3n despu\u00e9s de otro programa<\/h5>\n<p>Una utilidad interesante de los archivos BAT consiste en encadenar<br \/>\nvarios comandos.<\/p>\n<p>Por ejemplo:<\/p>\n<div id=\"cb14\" class=\"sourceCode\">\n<pre class=\"sourceCode bat\"><code class=\"sourceCode dosbat\"><span id=\"cb14-1\"><span class=\"kw\">@<\/span><span class=\"bu\">echo off<\/span><\/span>\n<span id=\"cb14-2\"><\/span>\n<span id=\"cb14-3\">backup.exe<\/span>\n<span id=\"cb14-4\"><\/span>\n<span id=\"cb14-5\"><span class=\"cf\">if<\/span> <span class=\"pp\">%<\/span><span class=\"va\">ERRORLEVEL<\/span><span class=\"pp\">%<\/span> <span class=\"kw\">EQU<\/span> 0 <span class=\"kw\">(<\/span><\/span>\n<span id=\"cb14-6\">    <span class=\"bu\">call<\/span> <span class=\"ot\">notificar.bat<\/span><\/span>\n<span id=\"cb14-7\"><span class=\"kw\">)<\/span><\/span><\/code><\/pre>\n<\/div>\n<p>En este ejemplo se ejecuta primero:<\/p>\n<pre class=\"text\"><code>backup.exe<\/code><\/pre>\n<p>y se consulta posteriormente su c\u00f3digo de salida.<\/p>\n<p>Podemos desarrollar el ejemplo para generar una notificaci\u00f3n<br \/>\ndiferente cuando se produzca un error:<\/p>\n<div id=\"cb16\" class=\"sourceCode\">\n<pre class=\"sourceCode bat\"><code class=\"sourceCode dosbat\"><span id=\"cb16-1\"><span class=\"kw\">@<\/span><span class=\"bu\">echo off<\/span><\/span>\n<span id=\"cb16-2\"><\/span>\n<span id=\"cb16-3\">backup.exe<\/span>\n<span id=\"cb16-4\"><\/span>\n<span id=\"cb16-5\"><span class=\"cf\">if<\/span> <span class=\"pp\">%<\/span><span class=\"va\">ERRORLEVEL<\/span><span class=\"pp\">%<\/span> <span class=\"kw\">EQU<\/span> 0 <span class=\"kw\">(<\/span><\/span>\n<span id=\"cb16-6\">    <span class=\"bu\">set<\/span> <span class=\"st\">\"<\/span><span class=\"va\">RESULTADO<\/span>=<span class=\"st\">La copia de seguridad ha terminado correctamente\"<\/span><\/span>\n<span id=\"cb16-7\"><span class=\"kw\">)<\/span> <span class=\"cf\">else<\/span> <span class=\"kw\">(<\/span><\/span>\n<span id=\"cb16-8\">    <span class=\"bu\">set<\/span> <span class=\"st\">\"<\/span><span class=\"va\">RESULTADO<\/span>=<span class=\"st\">ERROR: la copia de seguridad ha fallado\"<\/span><\/span>\n<span id=\"cb16-9\"><span class=\"kw\">)<\/span><\/span><\/code><\/pre>\n<\/div>\n<p>A continuaci\u00f3n podemos utilizar el valor de <code>RESULTADO<\/code> como contenido del mensaje enviado a Slack.<\/p>\n<p>El principio es exactamente el mismo que en PHP y AppleScript:<br \/>\nnuestro programa detecta un acontecimiento y realiza una petici\u00f3n a la<br \/>\nAPI de Slack.<\/p>\n<h3 id=\"comprobar-la-respuesta-de-slack\">Comprobar la respuesta de<br \/>\nSlack<\/h3>\n<p>Hay un detalle importante que no debemos ignorar en una<br \/>\nimplementaci\u00f3n real.<\/p>\n<p>No basta con comprobar que la conexi\u00f3n HTTPS se ha realizado<br \/>\ncorrectamente.<\/p>\n<p>La API de Slack devuelve un documento JSON indicando si la operaci\u00f3n<br \/>\nha tenido \u00e9xito.<\/p>\n<p>Una respuesta correcta contendr\u00e1 un valor equivalente a:<\/p>\n<div id=\"cb17\" class=\"sourceCode\">\n<pre class=\"sourceCode json\"><code class=\"sourceCode json\"><span id=\"cb17-1\"><span class=\"fu\">{<\/span><\/span>\n<span id=\"cb17-2\">    <span class=\"dt\">\"ok\"<\/span><span class=\"fu\">:<\/span> <span class=\"kw\">true<\/span><\/span>\n<span id=\"cb17-3\"><span class=\"fu\">}<\/span><\/span><\/code><\/pre>\n<\/div>\n<p>Mientras que, si existe alg\u00fan problema, recibiremos una respuesta<br \/>\nsimilar a:<\/p>\n<div id=\"cb18\" class=\"sourceCode\">\n<pre class=\"sourceCode json\"><code class=\"sourceCode json\"><span id=\"cb18-1\"><span class=\"fu\">{<\/span><\/span>\n<span id=\"cb18-2\">    <span class=\"dt\">\"ok\"<\/span><span class=\"fu\">:<\/span> <span class=\"kw\">false<\/span><span class=\"fu\">,<\/span><\/span>\n<span id=\"cb18-3\">    <span class=\"dt\">\"error\"<\/span><span class=\"fu\">:<\/span> <span class=\"st\">\"...\"<\/span><\/span>\n<span id=\"cb18-4\"><span class=\"fu\">}<\/span><\/span><\/code><\/pre>\n<\/div>\n<p>Por tanto, nuestros scripts deber\u00edan comprobar el campo<br \/>\n<code>ok<\/code> cuando sea importante asegurarnos de que la notificaci\u00f3n ha sido aceptada por Slack.<\/p>\n<p>Esto permite detectar situaciones como un token incorrecto, permisos<br \/>\ninsuficientes o un canal al que la aplicaci\u00f3n no puede acceder.<\/p>\n<h2 id=\"seguridad\">Seguridad<\/h2>\n<p>El elemento m\u00e1s delicado de todo este sistema es el token OAuth del<br \/>\nbot.<\/p>\n<p>Debemos tratarlo igual que una contrase\u00f1a.<\/p>\n<p>En particular, conviene seguir varias reglas:<\/p>\n<ul>\n<li>no publicarlo en GitHub ni en otros repositorios p\u00fablicos;<\/li>\n<li>no incluirlo en art\u00edculos, capturas de pantalla o<br \/>\ndocumentaci\u00f3n;<\/li>\n<li>evitar almacenarlo directamente dentro del c\u00f3digo;<\/li>\n<li>impedir que pueda descargarse desde nuestro servidor web;<\/li>\n<li>utilizar variables de entorno o mecanismos seguros de almacenamiento<br \/>\nde credenciales;<\/li>\n<li>revocarlo inmediatamente si sospechamos que ha quedado<br \/>\nexpuesto.<\/li>\n<\/ul>\n<p>Tambi\u00e9n es aconsejable conceder a la aplicaci\u00f3n \u00fanicamente los<br \/>\npermisos que necesita.<\/p>\n<p>Para los ejemplos de este tutorial nos interesa utilizar<br \/>\n<em>chat:write<\/em>.<\/p>\n<p>No existe ninguna raz\u00f3n para conceder acceso a mensajes, usuarios,<br \/>\narchivos u otros recursos si nuestra aplicaci\u00f3n solamente necesita<br \/>\npublicar una notificaci\u00f3n.<\/p>\n<p>Aplicar el principio del m\u00ednimo privilegio reduce las consecuencias<br \/>\nde una posible filtraci\u00f3n del token.<\/p>\n<h3 id=\"no-utilizar-slack-como-sistema-de-registro\">No utilizar Slack<br \/>\ncomo sistema de registro<\/h3>\n<p>Aunque podemos enviar mensajes autom\u00e1ticos, Slack no deber\u00eda<br \/>\nconvertirse en el registro completo de actividad de nuestro<br \/>\nservidor.<\/p>\n<p>No ser\u00eda razonable, por ejemplo, enviar una notificaci\u00f3n por cada<br \/>\npetici\u00f3n HTTP recibida por una p\u00e1gina web.<\/p>\n<p>Las notificaciones deben reservarse para acontecimientos que<br \/>\nrealmente queremos conocer.<\/p>\n<p>El env\u00edo masivo puede encontrarse con los l\u00edmites de frecuencia<br \/>\nestablecidos por Slack.<\/p>\n<p>Para almacenar grandes cantidades de acontecimientos debemos utilizar<br \/>\narchivos de registro, bases de datos o plataformas espec\u00edficas de<br \/>\nmonitorizaci\u00f3n. Slack puede actuar como la \u00faltima etapa del sistema y<br \/>\navisarnos \u00fanicamente cuando ocurre algo que requiere nuestra<br \/>\natenci\u00f3n.<\/p>\n<h4 id=\"limitaciones-de-la-cuenta-gratuita\">Limitaciones de la cuenta<br \/>\ngratuita<\/h4>\n<p>El plan gratuito de Slack es suficiente para un sistema dom\u00e9stico o<br \/>\nun peque\u00f1o sistema de notificaciones como el descrito en este tutorial,<br \/>\npero debemos tener presentes sus restricciones.<\/p>\n<p>Slack tambi\u00e9n establece limitaciones sobre el historial disponible en<br \/>\nlos espacios de trabajo gratuitos y aplica l\u00edmites de frecuencia a las<br \/>\nllamadas realizadas contra su API.<\/p>\n<p>Estas restricciones no suelen representar un problema para un sistema<br \/>\nque env\u00eda unas pocas alertas al d\u00eda, pero son importantes si pretendemos<br \/>\nutilizar Slack para registrar autom\u00e1ticamente una gran cantidad de<br \/>\nacontecimientos.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>En la actualidad trabajamos con m\u00e1quinas que realizan procesos largos o, incluso, esas m\u00e1quinas est\u00e1n lejos de nosotros. Cuando sucede alg\u00fan evento que nos interese, como que ha terminado de procesar un fichero grande o nuestro sitio web est\u00e1 recibiendo un ataque, recibir una notificaci\u00f3n de este hecho podr\u00eda ayudarnos a ser m\u00e1s proactivos y &hellip; <\/p>\n<p class=\"link-more\"><a href=\"https:\/\/programaraciegas.net\/?p=1382\" class=\"more-link\">Continuar leyendo<span class=\"screen-reader-text\"> \u00abC\u00f3mo enviar notificaciones a Slack desde PHP, macOS y Windows\u00bb<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[25,80,37,42,38,6,92,23,39],"tags":[122,459,560],"class_list":["post-1382","post","type-post","status-publish","format-standard","hentry","category-android","category-applescript","category-herramientas-software","category-ios","category-macos-x","category-programacion","category-servicios-de-internet","category-sistemas-operativos","category-windows","tag-notificaciones","tag-slack","tag-tutorial"],"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/programaraciegas.net\/index.php?rest_route=\/wp\/v2\/posts\/1382","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/programaraciegas.net\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/programaraciegas.net\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/programaraciegas.net\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/programaraciegas.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1382"}],"version-history":[{"count":0,"href":"https:\/\/programaraciegas.net\/index.php?rest_route=\/wp\/v2\/posts\/1382\/revisions"}],"wp:attachment":[{"href":"https:\/\/programaraciegas.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1382"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/programaraciegas.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1382"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/programaraciegas.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1382"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}