<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[Cindr.org]]></title><description><![CDATA[Cindr.org is a platform to get easy and simple tutorials and guides on topics such as programming]]></description><link>https://cindr.org/</link><image><url>https://cindr.org/favicon.png</url><title>Cindr.org</title><link>https://cindr.org/</link></image><generator>Ghost 5.2</generator><lastBuildDate>Mon, 13 Apr 2026 10:19:48 GMT</lastBuildDate><atom:link href="https://cindr.org/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[How to create a simple, intuitive search in JS + HTML]]></title><description><![CDATA[<p>As a second installment to the &quot;simple, intuitive&quot; solution, I am to walk you through a HTML search that I&apos;ve used with live websites. It&apos;s not the most robust, but its simplicty is worth sharing, and can be useful to implement in simple use</p>]]></description><link>https://cindr.org/how-to-create-a-simple-intuitive-search-in-js-html/</link><guid isPermaLink="false">67634b7136dacd00019c0d36</guid><dc:creator><![CDATA[Martin B]]></dc:creator><pubDate>Wed, 18 Dec 2024 22:51:20 GMT</pubDate><media:content url="https://cindr.org/content/images/2024/12/MacBook-Pro-16_---15-1-.png" medium="image"/><content:encoded><![CDATA[<img src="https://cindr.org/content/images/2024/12/MacBook-Pro-16_---15-1-.png" alt="How to create a simple, intuitive search in JS + HTML"><p>As a second installment to the &quot;simple, intuitive&quot; solution, I am to walk you through a HTML search that I&apos;ve used with live websites. It&apos;s not the most robust, but its simplicty is worth sharing, and can be useful to implement in simple use cases.</p><p>For example, I use it on a page that has 40x cards, and its a quick way to navigate to a card. I don&apos;t need fuzzy searching or to query 100,000 rows.</p><p>However, searching is an important UI, and this tutorial covers more than just basic string matching on an input field after clicking a button.</p><p>Complete code is at the bottom of this page, but I will walk you step by step!</p><h2 id="video-tutorial">Video Tutorial</h2><p></p><p></p><h2 id="0-boilerplate">0. Boilerplate</h2><p>Every project starts with boilerplate HTML. Here I have a set of cards, and a table that we can use as search data.</p><pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
&lt;head&gt;
    &lt;meta charset=&quot;UTF-8&quot;&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&gt;
    &lt;title&gt;Document&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;style&gt;
        #card-container {
          display: flex;
          gap: 16px;
          flex-wrap: wrap;
          justify-content: center;
        }
      
        .card {
          border: 1px solid #ccc;
          border-radius: 8px;
          padding: 16px;
          width: 200px;
          text-align: center;
        }
      
        table {
          margin-top: 20px;
          border-collapse: collapse;
          width: 100%;
          max-width: 600px;
          text-align: left;
        }
      
        th, td {
          border: 1px solid #ccc;
          padding: 8px;
        }
      
        th {
          background-color: #f4f4f4;
        }

        .table-container{
            display: flex;
            justify-content: center;
        }
      &lt;/style&gt;
      
      &lt;input id=&quot;cardSearchInput&quot; type=&quot;text&quot; placeholder=&quot;Search...&quot;&gt;
    
      &lt;div id=&quot;card-container&quot;&gt;
        &lt;div class=&quot;card&quot;&gt;
          &lt;h3&gt;Customer 1&lt;/h3&gt;
          &lt;p&gt;Name: Jane Doe&lt;/p&gt;
          &lt;p&gt;Email: jane.doe@example.com&lt;/p&gt;
          &lt;p&gt;Phone: (123) 456-7890&lt;/p&gt;
        &lt;/div&gt;
        &lt;div class=&quot;card&quot;&gt;
          &lt;h3&gt;Customer 2&lt;/h3&gt;
          &lt;p&gt;Name: John Smith&lt;/p&gt;
          &lt;p&gt;Email: john.smith@example.com&lt;/p&gt;
          &lt;p&gt;Phone: (987) 654-3210&lt;/p&gt;
        &lt;/div&gt;
        &lt;div class=&quot;card&quot;&gt;
          &lt;h3&gt;Customer 3&lt;/h3&gt;
          &lt;p&gt;Name: Emily Davis&lt;/p&gt;
          &lt;p&gt;Email: emily.davis@example.com&lt;/p&gt;
          &lt;p&gt;Phone: (555) 123-4567&lt;/p&gt;
        &lt;/div&gt;
        &lt;div class=&quot;card&quot;&gt;
          &lt;h3&gt;Customer 4&lt;/h3&gt;
          &lt;p&gt;Name: Michael Brown&lt;/p&gt;
          &lt;p&gt;Email: michael.brown@example.com&lt;/p&gt;
          &lt;p&gt;Phone: (444) 987-6543&lt;/p&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;input id=&quot;tableSearchInput&quot; type=&quot;text&quot; placeholder=&quot;Search...&quot;&gt;
      &lt;div class=&quot;table-container&quot;&gt;
          &lt;table&gt;
            &lt;thead&gt;
              &lt;tr&gt;
                &lt;th&gt;Product Name&lt;/th&gt;
                &lt;th&gt;Category&lt;/th&gt;
                &lt;th&gt;Price&lt;/th&gt;
              &lt;/tr&gt;
            &lt;/thead&gt;
            &lt;tbody id=&quot;table-container&quot;&gt;
              &lt;tr&gt;
                &lt;td&gt;Wireless Headphones&lt;/td&gt;
                &lt;td&gt;Electronics&lt;/td&gt;
                &lt;td&gt;$99.99&lt;/td&gt;
              &lt;/tr&gt;
              &lt;tr&gt;
                &lt;td&gt;Office Chair&lt;/td&gt;
                &lt;td&gt;Furniture&lt;/td&gt;
                &lt;td&gt;$149.99&lt;/td&gt;
              &lt;/tr&gt;
              &lt;tr&gt;
                &lt;td&gt;Smartphone&lt;/td&gt;
                &lt;td&gt;Electronics&lt;/td&gt;
                &lt;td&gt;$699.99&lt;/td&gt;
              &lt;/tr&gt;
              &lt;tr&gt;
                &lt;td&gt;Coffee Maker&lt;/td&gt;
                &lt;td&gt;Appliances&lt;/td&gt;
                &lt;td&gt;$49.99&lt;/td&gt;
              &lt;/tr&gt;
              &lt;tr&gt;
                &lt;td&gt;Running Shoes&lt;/td&gt;
                &lt;td&gt;Sportswear&lt;/td&gt;
                &lt;td&gt;$89.99&lt;/td&gt;
              &lt;/tr&gt;
            &lt;/tbody&gt;
          &lt;/table&gt;
      &lt;/div&gt;
      
&lt;/body&gt;</code></pre><h2 id="step-1-bind-our-elements">Step 1. Bind our elements</h2><p>We need to a) know where the search text is coming from and b) know where to search. In some contexts, this is called a needle &amp; a haystack, shown here:</p><figure class="kg-card kg-image-card"><img src="https://cindr.org/content/images/2024/12/image.png" class="kg-image" alt="How to create a simple, intuitive search in JS + HTML" loading="lazy" width="1812" height="561" srcset="https://cindr.org/content/images/size/w600/2024/12/image.png 600w, https://cindr.org/content/images/size/w1000/2024/12/image.png 1000w, https://cindr.org/content/images/size/w1600/2024/12/image.png 1600w, https://cindr.org/content/images/2024/12/image.png 1812w" sizes="(min-width: 720px) 720px"></figure><p>Understading our haystack is two-fold. First, and more simply, it&apos;s where we are searching through. However, secondly, and maybe more importantly, it&apos;s determining the smallest unit of what we return when we get a positive result.</p><figure class="kg-card kg-image-card"><img src="https://cindr.org/content/images/2024/12/image-1.png" class="kg-image" alt="How to create a simple, intuitive search in JS + HTML" loading="lazy" width="1629" height="915" srcset="https://cindr.org/content/images/size/w600/2024/12/image-1.png 600w, https://cindr.org/content/images/size/w1000/2024/12/image-1.png 1000w, https://cindr.org/content/images/size/w1600/2024/12/image-1.png 1600w, https://cindr.org/content/images/2024/12/image-1.png 1629w" sizes="(min-width: 720px) 720px"></figure><p>As shown above, do we show the user the whole card that has a positive text match, or just the paragraph of which it exists in. It&apos;s up to you! (The developer, or what the client wants :)). However, it&apos;s common that you would return the card, snippet, row, etc. that the data lives in to give context to the data. But if it&apos;s the paragraph the user would expect to see, you would give them that.</p><p>We will define this as:</p><pre><code class="language-js">    let searchInput = document.getElementById(&apos;cardSearchInput&apos;);
    let cards = document.querySelectorAll(&apos;.card&apos;);</code></pre><p>We are giving our search in &quot;searchInput&quot;, but we are searching through the texts of .cards, so each .card is a unit; and we will also return the whole .card if we find a positive match within it.</p><p>Then we will bind a keyup function, so that our search is live to what the user is pressing. This is doable in &quot;smaller&quot; datasets, and will make it feel responsive.</p><pre><code class="language-js">    searchInput.addEventListener(&apos;keyup&apos;, function(event){
		let searchText = event.target.value.toLowerCase();
		//search code
    }</code></pre><p>We now need to compare the search text against what is in each card. We visit each card individually, and ask, &quot;does this card contain the text we are interested in?&quot;</p><pre><code class="language-js">        cards.forEach(function(cardElement){
            let cardText = cardElement.innerText.toLowerCase();
            if(cardText.includes(searchText)){
                cardElement.style.display = &apos;block&apos;;
            } else {
                cardElement.style.display = &apos;none&apos;;
            }
        });</code></pre><p>If the answer is yes, give the WHOLE card a style of block, if not, hide it.</p><p>That&apos;s it.</p><pre><code class="language-js">    let searchInput = document.getElementById(&apos;cardSearchInput&apos;);
    let cards = document.querySelectorAll(&apos;.card&apos;);
    //let cards = Array.from(document.getElementById(&apos;card-container&apos;).children); // returns a live HTMLCollection, so we convert it to an array

    searchInput.addEventListener(&apos;keyup&apos;, function(event){
        
        cards.forEach(function(cardElement){
            let cardText = cardElement.innerText.toLowerCase();
            if(cardText.includes(searchText)){
                cardElement.style.display = &apos;block&apos;;
            } else {
                cardElement.style.display = &apos;none&apos;;
            }
        });
    });</code></pre><p>If you want to abstract it, so you can bind it to any search input; search set combination, I have created a very similar function here</p><pre><code class="language-js">    function bindSearch(inputId, parentId, isTable = false){
        let searchInput = document.getElementById(inputId);
        let searchItems = Array.from(document.getElementById(parentId).children); // returns a live HTMLCollection, so we convert it to an array

        let showStyle = &apos;block&apos;; 
        if(isTable){
            showStyle = &apos;table-row&apos;; // when block is applied to a tr, the columns will collapse
        }

        searchInput.addEventListener(&apos;keyup&apos;, function(event){
            let searchText = event.target.value.toLowerCase();

            searchItems.forEach(function(searchElement){
                let cardText = searchElement.innerText.toLowerCase();
                if(cardText.includes(searchText)){
                    searchElement.style.display = showStyle;
                } else {
                    searchElement.style.display = &apos;none&apos;;
                }
            });
        });
    }
</code></pre><p>Notice the changes</p><ol><li>I take in an inputId, and parentId and isTable</li><li>Instead of having to give a class to each search element, I target the parent, and and notice that those &quot;.cards&quot; that we had earlier, are all just first level children of the parent</li><li>We have to change the showStyle, if it&apos;s a table. Display block will collapse the table columns into a flex behavior</li></ol><pre><code class="language-js">bindSearch(&apos;tableSearchInput&apos;, &apos;table-container&apos;, true);</code></pre><p>After defining the function, call it to bind everything!</p>]]></content:encoded></item><item><title><![CDATA[How to create a simple, intuitive vanilla JS carousel]]></title><description><![CDATA[<p>Carousels are one of those things in web development that can be made to be very complicated. If you look for tutorials out there, there are many great ones, but a lot of them jump to complex animations, extra features, etc. But the simpler ones only flash between divs/images,</p>]]></description><link>https://cindr.org/how-to-create-a-simple-intuitive-vanilla-js-carousel/</link><guid isPermaLink="false">6734f1d536dacd00019c0cbf</guid><dc:creator><![CDATA[Martin B]]></dc:creator><pubDate>Wed, 13 Nov 2024 19:14:20 GMT</pubDate><media:content url="https://cindr.org/content/images/2024/11/clipboard_2024-11-13_14-13-15.png" medium="image"/><content:encoded><![CDATA[<img src="https://cindr.org/content/images/2024/11/clipboard_2024-11-13_14-13-15.png" alt="How to create a simple, intuitive vanilla JS carousel"><p>Carousels are one of those things in web development that can be made to be very complicated. If you look for tutorials out there, there are many great ones, but a lot of them jump to complex animations, extra features, etc. But the simpler ones only flash between divs/images, instead of sliding through multiple elements on a screen.</p><p>In this tutorial, I will walk you through an intuitive understanding of Javascript carousels.</p><h2 id="video-guide">Video Guide:</h2><figure class="kg-card kg-embed-card"><iframe width="200" height="113" src="https://www.youtube.com/embed/Zd8170gwwmc?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen title="How to create a simple, intuitive vanilla Javascript Carousel (with explanation)"></iframe></figure><p>This is a beginner tutorial, aimed to make an intutive JS carousel, it is not necessarily the most correct or &quot;clever&quot;.</p><h2 id="step-1-starter-code">Step 1: Starter code</h2><p>Here is some starter code, with very basic HTML and CSS to get us started.</p><pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
&lt;head&gt;
    &lt;meta charset=&quot;UTF-8&quot;&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&gt;
    &lt;title&gt;Carousel&lt;/title&gt;
&lt;/head&gt;
&lt;style&gt;

    body{
        font-family:sans-serif
    }
    #container{
        background:#eee;
        height:150px;
        width:500px;
        margin:auto;
        display:flex;
        justify-content:space-between;
        align-items: center;
    }
    #carousel-track{
        width:250px;
        height:64px;
    }
    .carousel-item{
        height:64px;
        width:64px;
        background:#777;
        color:#FFF;
    }
&lt;/style&gt;
&lt;body&gt;
    &lt;div id=&quot;container&quot;&gt;
        &lt;button&gt;&lt;&lt;/button&gt;
        &lt;div id=&quot;carousel-track&quot;&gt;
            &lt;div class=&quot;carousel-item&quot;&gt;A&lt;/div&gt;
            &lt;div class=&quot;carousel-item&quot;&gt;B&lt;/div&gt;
            &lt;div class=&quot;carousel-item&quot;&gt;C&lt;/div&gt;
            &lt;div class=&quot;carousel-item&quot;&gt;D&lt;/div&gt;
            &lt;div class=&quot;carousel-item&quot;&gt;E&lt;/div&gt;
            &lt;div class=&quot;carousel-item&quot;&gt;F&lt;/div&gt;
        &lt;/div&gt;
        &lt;button &gt;&gt;&lt;/button&gt;
    &lt;/div&gt;
&lt;/body&gt;

&lt;script&gt;

&lt;/script&gt;
&lt;/html&gt;</code></pre><p>You should see something like this:</p><figure class="kg-card kg-image-card"><img src="https://cindr.org/content/images/2024/11/image.png" class="kg-image" alt="How to create a simple, intuitive vanilla JS carousel" loading="lazy" width="1316" height="817" srcset="https://cindr.org/content/images/size/w600/2024/11/image.png 600w, https://cindr.org/content/images/size/w1000/2024/11/image.png 1000w, https://cindr.org/content/images/2024/11/image.png 1316w" sizes="(min-width: 720px) 720px"></figure><h2 id="step-2-style-the-carousel-into-a-row">Step 2: Style the carousel into a row</h2><p>The first thing we want to do is style the css further, and get all of our boxes into 1 row (we will call this row the <strong>#carousel-track</strong>.</p><p>We will add the following classes to #carousel-track</p><pre><code class="language-css">    #carousel-track{
        border:1px solid red; /* Shows us what we are working with */
        width:250px;
        height:64px;
        white-space: nowrap; /* Prevents wrapping */
        overflow:hidden;
        font-size:0px;
    }</code></pre><p>The weird ``<em>font-size: 0px;``</em> is to remove unwanted spacing introduced by blank HTML interacting with the inline-block elements that we will make as children to .carousel-item</p><figure class="kg-card kg-image-card"><img src="https://cindr.org/content/images/2024/11/image-1.png" class="kg-image" alt="How to create a simple, intuitive vanilla JS carousel" loading="lazy" width="849" height="491" srcset="https://cindr.org/content/images/size/w600/2024/11/image-1.png 600w, https://cindr.org/content/images/2024/11/image-1.png 849w" sizes="(min-width: 720px) 720px"></figure><p>Ok, we removed the overflow, now add <em>inline-block</em>, recreate the <em>font size</em> removed in the parent, and add a small gap between the items;</p><pre><code class="language-css">    .carousel-item{
        height:64px;
        width:64px;
        background:#333;

        display:inline-block;   
        color:#FFF;
        font-size:16px;
        margin-right:6px;
     
    }</code></pre><figure class="kg-card kg-image-card"><img src="https://cindr.org/content/images/2024/11/image-2.png" class="kg-image" alt="How to create a simple, intuitive vanilla JS carousel" loading="lazy" width="868" height="444" srcset="https://cindr.org/content/images/size/w600/2024/11/image-2.png 600w, https://cindr.org/content/images/2024/11/image-2.png 868w" sizes="(min-width: 720px) 720px"></figure><p>Great! Now our carousel is actually in a row, and the overflow of the carousel is bounded by our track window!</p><h2 id="step-3-javascript-functionality">Step 3: Javascript Functionality</h2><p>Lets add onclick calls to our main function to our two buttons:</p><pre><code class="language-html">    &lt;div id=&quot;container&quot;&gt;
        &lt;button onclick=&quot;moveCarousel(&apos;backward&apos;)&quot;&gt;&lt;&lt;/button&gt;
        &lt;div id=&quot;carousel-track&quot;&gt;
            &lt;div class=&quot;carousel-item&quot;&gt;A&lt;/div&gt;
            &lt;div class=&quot;carousel-item&quot;&gt;B&lt;/div&gt;
            &lt;div class=&quot;carousel-item&quot;&gt;C&lt;/div&gt;
            &lt;div class=&quot;carousel-item&quot;&gt;D&lt;/div&gt;
            &lt;div class=&quot;carousel-item&quot;&gt;E&lt;/div&gt;
            &lt;div class=&quot;carousel-item&quot;&gt;F&lt;/div&gt;
        &lt;/div&gt;
        &lt;button onclick=&quot;moveCarousel(&apos;forward&apos;)&quot;&gt;&gt;&lt;/button&gt;
    &lt;/div&gt;</code></pre><p>Clearly, we are calling one function, with two parameters to move us forward or backward.</p><p>In our Javascript, let&apos;s create this function and add logic to at least just move something forward:</p><p>Had we added </p><pre><code class="language-css">.carousel-item{
    transform: translateX(20px)
}</code></pre><p>to carousel item, we would&apos;ve moved all of our items to the right (+x) by 20 pixels. We want to move the whole class, because we want everyone to move, not just a single element.</p><p>However, to move &quot;forward&quot; we have to pull everything to the left, to expose elements on the right. So, forward motion should be translated -x pixels.</p><p>To add this to our function, let&apos;s move all of our elements forward -x, on each click:</p><pre><code class="language-js">    function moveCarousel(direction) {
        const offset = 68;
        document.querySelectorAll(&apos;.carousel-item&apos;).forEach(carouselItemElement =&gt;{
            carouselItemElement.style.transform = `translateX(-${offset}px)`;
        })
    }</code></pre><p>If you want to see the animation better, add a transition to the elements:</p><pre><code class="language-css">    .carousel-item{
        height:64px;
        width:64px;
        background:#333;

        display:inline-block;   
        color:#FFF;
        font-size:16px;
        margin-right:6px;

        transition: transform 0.3s ease;
    }</code></pre><p>Notice that this only works on the first click? Because our elements have been moved <strong>TO </strong>the -68px position, and every other click, they are already there. So we are not adding to the position, we are just setting it.</p><p>So let&apos;s &quot;add to our position&quot;, by multiplying the -68 by the number of times we have clicked the button, and increase the position everytime we click it.</p><pre><code class="language-js">    var position = 0;
    function moveCarousel(direction) {
        position++;
        const offset = 68*position;
        
        document.querySelectorAll(&apos;.carousel-item&apos;).forEach(carouselItemElement =&gt;{
            carouselItemElement.style.transform = `translateX(-${offset}px)`;
        })
    }</code></pre><p>Perfect, now let&apos;s move our position backward for the the other button.</p><p>In order to do this, we need to decrease our offset, therefore, just decrease our &quot;desired&quot; position</p><pre><code class="language-js">    var position = 0;
    function moveCarousel(direction) {
        if(direction==&apos;forward&apos;){
            position++;
        }
        else if(direction==&apos;backward&apos;){
            position--;
        }

        const offset = 68*position;

        document.querySelectorAll(&apos;.carousel-item&apos;).forEach(carouselItemElement =&gt;{
            carouselItemElement.style.transform = `translateX(-${offset}px)`;
        })
    }</code></pre><p>Finally, let&apos;s add a gaurd and prevent the function running forward if it&apos;s over the boundry, or backward, if it&apos;s less than 0.</p><pre><code class="language-js">    var position = 0;

    function moveCarousel(direction) {
        if(direction==&apos;forward&apos;){
            if(position==3){
                return false;
            }
            position++;
        }
        else if(direction==&apos;backward&apos;){
            if(position==0){
                return false;
            }
            position--;
        }

        const offset = 68 * position;
        document.querySelectorAll(&apos;.carousel-item&apos;).forEach(carouselItemElement =&gt;{
            carouselItemElement.style.transform = `translateX(-${offset}px)`;
        })
    }</code></pre><p>That&apos;s it! You&apos;re done! From here, you can expand on it as you wish. </p><h2 id="full-code">Full Code:</h2><pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
&lt;head&gt;
    &lt;meta charset=&quot;UTF-8&quot;&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&gt;
    &lt;title&gt;Carousel&lt;/title&gt;
&lt;/head&gt;
&lt;style&gt;

    body{
        font-family:sans-serif
    }
    #container{
        background:#eee;
        height:150px;
        width:500px;
        margin:auto;
        display:flex;
        justify-content:space-between;
        align-items: center;
    }
    #carousel-track{
        border:1px solid red;
        width:250px;
        height:64px;
        white-space: nowrap; /* Prevents wrapping */
        overflow:hidden;
        font-size:0px;
    }
    .carousel-item{
        height:64px;
        width:64px;
        background:#333;

        display:inline-block;   
        color:#FFF;
        font-size:16px;
        margin-right:6px;

        transition: transform 0.3s ease;
    }
&lt;/style&gt;
&lt;body&gt;
    &lt;div id=&quot;container&quot;&gt;
        &lt;button onclick=&quot;moveCarousel(&apos;backward&apos;)&quot;&gt;&lt;&lt;/button&gt;
        &lt;div id=&quot;carousel-track&quot;&gt;
            &lt;div class=&quot;carousel-item&quot;&gt;A&lt;/div&gt;
            &lt;div class=&quot;carousel-item&quot;&gt;B&lt;/div&gt;
            &lt;div class=&quot;carousel-item&quot;&gt;C&lt;/div&gt;
            &lt;div class=&quot;carousel-item&quot;&gt;D&lt;/div&gt;
            &lt;div class=&quot;carousel-item&quot;&gt;E&lt;/div&gt;
            &lt;div class=&quot;carousel-item&quot;&gt;F&lt;/div&gt;
        &lt;/div&gt;
        &lt;button onclick=&quot;moveCarousel(&apos;forward&apos;)&quot;&gt;&gt;&lt;/button&gt;
    &lt;/div&gt;
&lt;/body&gt;

&lt;script&gt;
    var position = 0;

    function moveCarousel(direction) {
        if(direction==&apos;forward&apos;){
            if(position==3){
                return false;
            }
            position++;
        }
        else if(direction==&apos;backward&apos;){
            if(position==0){
                return false;
            }
            position--;
        }

        const offset = 68 * position;
        document.querySelectorAll(&apos;.carousel-item&apos;).forEach(carouselItemElement =&gt;{
            carouselItemElement.style.transform = `translateX(-${offset}px)`;
        })
    }
&lt;/script&gt;
&lt;/html&gt;</code></pre>]]></content:encoded></item><item><title><![CDATA[How to get a Discord User's Server Roles using PHP and Redirect With Simple Permissions]]></title><description><![CDATA[<p>Here is the scenario. You want to log a user into your website, and then see if they have the required role (from your discord server) to view something on your site. In my example, I will redirect <strong>admins</strong> to a special page, <strong>moderators</strong> to their page, and the rest</p>]]></description><link>https://cindr.org/how-to-get-a-discord-users-server-roles-using-php-and-redirect-with-simple-permissions/</link><guid isPermaLink="false">64c5762e2635b20001363e62</guid><dc:creator><![CDATA[Martin B]]></dc:creator><pubDate>Sat, 29 Jul 2023 20:48:34 GMT</pubDate><media:content url="https://cindr.org/content/images/2023/07/MacBook-Pro-16_---2--2-.png" medium="image"/><content:encoded><![CDATA[<img src="https://cindr.org/content/images/2023/07/MacBook-Pro-16_---2--2-.png" alt="How to get a Discord User&apos;s Server Roles using PHP and Redirect With Simple Permissions"><p>Here is the scenario. You want to log a user into your website, and then see if they have the required role (from your discord server) to view something on your site. In my example, I will redirect <strong>admins</strong> to a special page, <strong>moderators</strong> to their page, and the rest of users to a regular, login protected page.</p><h3 id="video-tutorial">Video Tutorial:</h3><figure class="kg-card kg-embed-card"><iframe width="200" height="113" src="https://www.youtube.com/embed/aT3rPC2SP58?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen title="How to get a Discord User&apos;s Server Roles using PHP and Redirect With Simple Permissions"></iframe></figure><h2 id="source-code">Source Code:</h2><p>Check out the GitHub if you want to start with a plug-n-play template:</p><h2 id="getting-started">Getting Started:</h2><p>Start with my <a href="https://www.youtube.com/watch?v=w5ZLlnid8g0"><strong>Login with Discord</strong> (PHP) tutorial on YouTube.</a> It&apos;s about 20 minutes, but will get you up to speed on how to set up your discord developer account, and make some API calls with PHP!</p><h2 id="1-update-your-oauth-url">1) Update your OAuth URL</h2><p>If you followed the tutorial, your redirect URL probably looks like this:</p><pre><code class="language-php">https://discord.com/api/oauth2/authorize?client_id=11349347517325240&amp;redirect_uri=http%3A%2F%2Flocalhost%3A5000%2Fsrc%2Fprocess-oauth.php&amp;response_type=code&amp;scope=identify
</code></pre><p>Because we only picked the <em>&quot;scope&quot; permission.</em></p><p>To get the user&apos;s roles, we need the <strong>guilds.members.read permission</strong> as well.</p><p>To add that into your URL, head on over to the Discord Developer Dashboard, and go to your application, and check the additional scope as seen here:</p><figure class="kg-card kg-image-card"><img src="https://cindr.org/content/images/2023/07/image-1.png" class="kg-image" alt="How to get a Discord User&apos;s Server Roles using PHP and Redirect With Simple Permissions" loading="lazy" width="1430" height="482" srcset="https://cindr.org/content/images/size/w600/2023/07/image-1.png 600w, https://cindr.org/content/images/size/w1000/2023/07/image-1.png 1000w, https://cindr.org/content/images/2023/07/image-1.png 1430w" sizes="(min-width: 720px) 720px"></figure><p>Now, copy the OAuth URL and paste it into your <strong>init-oauth.php</strong> file.</p><pre><code class="language-php">&lt;?php

$discord_url = &quot;https://discord.com/api/oauth2/authorize?client_id=1134934751732572240&amp;redirect_uri=http%3A%2F%2Flocalhost%3A5000%2Fsrc%2Fprocess-oauth.php&amp;response_type=code&amp;scope=identify%20guilds%20guilds.members.read&quot;;
header(&quot;Location: $discord_url&quot;);
exit();

?&gt;</code></pre><h2 id="2-update-your-api-page-process-oauthphp">2) Update your API Page (process-oauth.php)</h2><p>Here is where we can now use our new permission to get information about the user&apos;s roles.</p><h3 id="get-your-servers-guild-id">Get your server&apos;s guild id</h3><p>Before we can do anything to find out the role of a user on a discord server, we needs its guild id.</p><p>Right click your discord server icon on discord, and select the bottom option &quot;<strong>Copy Server ID&quot;</strong></p><figure class="kg-card kg-image-card"><img src="https://cindr.org/content/images/2023/07/image-2.png" class="kg-image" alt="How to get a Discord User&apos;s Server Roles using PHP and Redirect With Simple Permissions" loading="lazy" width="256" height="528"></figure><p>For example, mine is <em>98672642795098937</em></p><h3 id="get-the-users-role-by-passing-the-guild-id">Get the user&apos;s role by passing the guild id</h3><p>In <strong>process-oauth.php, </strong>let&apos;s make a function that takes in the access-token discord gave us, and search &quot;our&quot; roles on a discord server by passing it&apos;s guild id</p><pre><code class="language-php">function getGuildObject($access_token, $guild_id){
        //requires the following scope: guilds.members.read
        $discord_api_url = &quot;https://discordapp.com/api&quot;;
        $header = array(&quot;Authorization: Bearer $access_token&quot;,&quot;Content-Type: application/x-www-form-urlencoded&quot;);
        $ch = curl_init();
        //set the url, number of POST vars, POST data
        curl_setopt($ch, CURLOPT_HTTPHEADER,$header);
        curl_setopt($ch,CURLOPT_URL, $discord_api_url.&apos;/users/@me/guilds/&apos;.$guild_id.&apos;/member&apos;);
        curl_setopt($ch,CURLOPT_POST, false);
        //curl_setopt($ch,CURLOPT_POSTFIELDS, $fields_string);
        curl_setopt($ch,CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
        $result = curl_exec($ch);
        $result = json_decode($result,true);
        return $result;
}</code></pre><p>The guild object will return something like this...</p><pre><code>Array
(
    [avatar] =&gt; 
    [communication_disabled_until] =&gt; 
    [flags] =&gt; 0
    [joined_at] =&gt; 2022-06-15T20:18:32.991000+00:00
    [nick] =&gt; 
    [pending] =&gt; 
    [premium_since] =&gt; 
    [roles] =&gt; Array
        (
            [0] =&gt; 1134940682650402968
        )

    [user] =&gt; Array
        (
            [id] =&gt; 118583685640355840
            [username] =&gt; Exit
            [avatar] =&gt; f2e98ae1156588254d4a6e3d9197fc8e
            [discriminator] =&gt; 9063
            [public_flags] =&gt; 0
            [flags] =&gt; 0
            [banner] =&gt; 
            [accent_color] =&gt; 
            [global_name] =&gt; Exit
            [avatar_decoration] =&gt; 
            [banner_color] =&gt; 
        )

    [mute] =&gt; 
    [deaf] =&gt; 
    [bio] =&gt; 
    [banner] =&gt; 
)</code></pre><p>Oh look! We have a <strong>roles</strong> array.</p><p>Let&apos;s access it, and test if it has a role that we care about.</p><pre><code class="language-php">$guild_roles = $guildObject[&apos;roles&apos;];
// see if roles has the correct role_id within the array

$role = &apos;user&apos;;
if(in_array(&apos;1134940795481370646&apos;, $guild_roles)){
    $role = &apos;admin&apos;;
}else if(in_array(&apos;1134940682650402968&apos;, $guild_roles)){
    $role = &apos;moderator&apos;;
}</code></pre><p>How do I know what 1134940795481370646 is? <br>Go to Server Settings &gt; Roles &gt;&gt; Copy Role Id</p><figure class="kg-card kg-image-card"><img src="https://cindr.org/content/images/2023/07/image-3.png" class="kg-image" alt="How to get a Discord User&apos;s Server Roles using PHP and Redirect With Simple Permissions" loading="lazy" width="1109" height="788" srcset="https://cindr.org/content/images/size/w600/2023/07/image-3.png 600w, https://cindr.org/content/images/size/w1000/2023/07/image-3.png 1000w, https://cindr.org/content/images/2023/07/image-3.png 1109w" sizes="(min-width: 720px) 720px"></figure><figure class="kg-card kg-image-card"><img src="https://cindr.org/content/images/2023/07/image-4.png" class="kg-image" alt="How to get a Discord User&apos;s Server Roles using PHP and Redirect With Simple Permissions" loading="lazy" width="872" height="181" srcset="https://cindr.org/content/images/size/w600/2023/07/image-4.png 600w, https://cindr.org/content/images/2023/07/image-4.png 872w" sizes="(min-width: 720px) 720px"></figure><p>Ok, now let&apos;s update the user&apos;s session, so we can keep track of their role. Also, we can <strong>redirect them</strong> to their special, protected page!</p><pre><code class="language-php">$_SESSION[&apos;logged_in&apos;] = true;
$_SESSION[&apos;userData&apos;] = [
    &apos;name&apos;=&gt;$result[&apos;username&apos;],
    &apos;discord_id&apos;=&gt;$result[&apos;id&apos;],
    &apos;avatar&apos;=&gt;$result[&apos;avatar&apos;],
    &apos;role&apos;=&gt;$role,
];


if($role==&apos;admin&apos;){
    header(&quot;location: admin-lounge.php&quot;);
}else if($role==&apos;moderator&apos;){
    header(&quot;location: moderator-lounge.php&quot;);
}else{
    header(&quot;location: dashboard.php&quot;);
}
exit();</code></pre><p>Here&apos;s an example of the <strong>admin-lounge.php</strong> page</p><pre><code class="language-php">&lt;?php

session_start();


if($_SESSION[&apos;userData&apos;][&apos;role&apos;]!=&apos;admin&apos;){
    header(&quot;location: index.php?error=not_admin&quot;);
    exit();
}
?&gt;
&lt;!doctype html&gt;
&lt;html&gt;
&lt;head&gt;
  &lt;meta charset=&quot;UTF-8&quot;&gt;
  &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&gt;
  &lt;link href=&quot;../dist/output.css&quot; rel=&quot;stylesheet&quot;&gt;
  &lt;link rel=&quot;stylesheet&quot; href=&quot;https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css&quot; integrity=&quot;sha512-KfkfwYDsLkIlwQp6LFnl8zNdLGxu9YAA1QvwINks4PhcElQSvqcyVLLD9aMhXd13uQjoXtEKNosOWaZqXgel0g==&quot; crossorigin=&quot;anonymous&quot; referrerpolicy=&quot;no-referrer&quot; /&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;div class=&apos;flex items-center justify-center h-screen font-bold&apos;&gt;&lt;?php echo &apos;Welcome, Admin&apos;; ?&gt;&lt;/div&gt;

&lt;/body&gt;
&lt;/html&gt;
</code></pre><p></p>]]></content:encoded></item><item><title><![CDATA[Create a simple sound output switch via Terminal in Linux & Bind it to a Key]]></title><description><![CDATA[<p>Since I&apos;ve switched from Windows to Linux, I&apos;ve tried to make sure that all the tools I had on my Windows OS were available on Linux. I had a program called <a href="https://soundswitch.aaflalo.me/">SoundSwitch</a> that let me bind a hotkey to toggle through audio devices.</p><p>It was a</p>]]></description><link>https://cindr.org/create-a-simple-sound-output-switch-via-terminal-in-linux-bind-it-to-a-key/</link><guid isPermaLink="false">63d289eb2635b20001363d4e</guid><dc:creator><![CDATA[Martin B]]></dc:creator><pubDate>Thu, 26 Jan 2023 14:20:00 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1506704888326-3b8834edb40a?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDJ8fHNvdW5kfGVufDB8fHx8MTY3NDc0Mjc4OQ&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1506704888326-3b8834edb40a?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDJ8fHNvdW5kfGVufDB8fHx8MTY3NDc0Mjc4OQ&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" alt="Create a simple sound output switch via Terminal in Linux &amp; Bind it to a Key"><p>Since I&apos;ve switched from Windows to Linux, I&apos;ve tried to make sure that all the tools I had on my Windows OS were available on Linux. I had a program called <a href="https://soundswitch.aaflalo.me/">SoundSwitch</a> that let me bind a hotkey to toggle through audio devices.</p><p>It was a simple program, but Linux makes this easy to do in a few lines.</p><p>I will be using Zorin OS for this tutorial as well.</p><h3 id="terminal-commands">Terminal Commands</h3><p>The first command you need is:</p><pre><code>pactl list sinks short | awk -F &apos;\t&apos; &apos;{print $1,$2,$5}&apos;</code></pre><p>This will list your audio sources and extract out relavant information into line delimited list.</p><p>Mine outputs:<br></p><pre><code>1 alsa_output.usb-Blue_Microphones_Yeti_Stereo_Microphone_REV8-00.iec958-stereo SUSPENDED
6 alsa_output.pci-0000_58_00.4.analog-stereo RUNNING
14 alsa_output.pci-0000_56_00.1.hdmi-stereo-extra4 SUSPENDED
</code></pre><p>Notice how there is an id, a reference name, and then its status. I realized that I want to switch between the Yeti output, and the analog-stero output.</p><p>The manual command for this is:</p><pre><code>pacmd set-default-sink NUMBER_ID_OF_SINK</code></pre><p>So for setting it back to my Yeti mic, I would execute:</p><pre><code>pacmd set-default-sink 1</code></pre><p>With this in mind, I have written a simple script to list out my inputs, get the selected input, and then swtich between the microphone or the speaker. Note, the IDs are dynamic, so you need to make sure you have a way to read/execute on them, and not just hard code in id=1, 6, 14, etc..</p><h3 id="making-a-bash-script-to-switch-between-sources">Making a bash script to switch between sources</h3><pre><code>#!/bin/bash

list=$(pactl list sinks short | awk -F &apos;\t&apos; &apos;{print $1,$2,$5}&apos;)

selected_index_string=$(echo &quot;$list&quot; | grep &quot;RUNNING&quot;)
yeti_index_string=$(echo &quot;$list&quot; | grep &quot;Yeti&quot;)
stero_index_string=$(echo &quot;$list&quot; | grep &quot;analog-stereo&quot;)

# Print the index of the line that has &quot;RUNNING&quot; in it
if [ &quot;${selected_index_string}&quot; == &quot;${yeti_index_string}&quot; ]; then
    pacmd set-default-sink ${stero_index_string:0:2} # speakers
else
    pacmd set-default-sink ${yeti_index_string:0:2} # microphone
fi</code></pre><h3 id="adding-a-keybind-to-execute-the-script">Adding a Keybind to execute the Script</h3><figure class="kg-card kg-image-card"><img src="https://cindr.org/content/images/2023/01/image.png" class="kg-image" alt="Create a simple sound output switch via Terminal in Linux &amp; Bind it to a Key" loading="lazy" width="1019" height="733" srcset="https://cindr.org/content/images/size/w600/2023/01/image.png 600w, https://cindr.org/content/images/size/w1000/2023/01/image.png 1000w, https://cindr.org/content/images/2023/01/image.png 1019w" sizes="(min-width: 720px) 720px"></figure><p>In ZorinOS go to settings, Keyboard Shortcuts, hit add new (the plus at the very bottom)</p><figure class="kg-card kg-image-card"><img src="https://cindr.org/content/images/2023/01/image-1.png" class="kg-image" alt="Create a simple sound output switch via Terminal in Linux &amp; Bind it to a Key" loading="lazy" width="616" height="339" srcset="https://cindr.org/content/images/size/w600/2023/01/image-1.png 600w, https://cindr.org/content/images/2023/01/image-1.png 616w"></figure><p>Name your shortcut, and give a path to the file </p><p>Make sure that you</p><pre><code>chmod +x script_name.sh</code></pre><p>To make it executable.</p><p>Thats it!</p>]]></content:encoded></item><item><title><![CDATA[How to Create a Simple Discord Bot using Python]]></title><description><![CDATA[<p>This will be a short guide on creating a simple Discord bot using Python.</p><h1 id="initial-setup">Initial Setup</h1><p>We will need to install a few things and setup our workspace before we get started.</p><h2 id="install-python">Install Python</h2><p>The first ting we will need is Python, you can download the latest version from <a href="https://www.python.org/downloads/">python.</a></p>]]></description><link>https://cindr.org/how-to-create-a-simple-discord-bot-using-python/</link><guid isPermaLink="false">62c492f92635b20001363ab2</guid><category><![CDATA[Python]]></category><category><![CDATA[Coding]]></category><dc:creator><![CDATA[Idean]]></dc:creator><pubDate>Thu, 27 Oct 2022 23:32:17 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1614680376739-414d95ff43df?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDF8fGRpc2NvcmR8ZW58MHx8fHwxNjY2MzAyNDQ5&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1614680376739-414d95ff43df?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDF8fGRpc2NvcmR8ZW58MHx8fHwxNjY2MzAyNDQ5&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" alt="How to Create a Simple Discord Bot using Python"><p>This will be a short guide on creating a simple Discord bot using Python.</p><h1 id="initial-setup">Initial Setup</h1><p>We will need to install a few things and setup our workspace before we get started.</p><h2 id="install-python">Install Python</h2><p>The first ting we will need is Python, you can download the latest version from <a href="https://www.python.org/downloads/">python.org</a> or using your package manager on Linux.</p><p>Make sure to select <strong>Add Python to PATH</strong> when installing on Windows.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cindr.org/content/images/2022/07/image-5.png" class="kg-image" alt="How to Create a Simple Discord Bot using Python" loading="lazy" width="666" height="410" srcset="https://cindr.org/content/images/size/w600/2022/07/image-5.png 600w, https://cindr.org/content/images/2022/07/image-5.png 666w"><figcaption>Python Setup Window</figcaption></figure><h2 id="setup-workspace">Setup Workspace</h2><h3 id="install-discordpy">Install Discord.py</h3><p>After installing python we can use pip to install Discord.py. Use <strong>one</strong> of the following commands depending on your OS and voice support.</p><p><strong>Windows</strong></p><pre><code>py -3 -m pip install -U discord.py</code></pre><pre><code>py -3 -m pip install -U discord.py[voice]
</code></pre><p><strong>Linux</strong></p><pre><code>python3 -m pip install -U discord.py</code></pre><pre><code>python3 -m pip install -U discord.py[voice]</code></pre><p>On Linux you will need these dependencies for voice. You can use this command for Debian based systems. You can usually just install these with your package manager.</p><!--kg-card-begin: markdown--><ul>
<li><a href="https://github.com/libffi/libffi">libffi</a></li>
<li><a href="https://github.com/saltstack/libnacl">libnacl</a></li>
<li><a href="https://packages.debian.org/python3-dev">python3-dev</a></li>
</ul>
<!--kg-card-end: markdown--><pre><code>apt install libffi-dev libnacl-dev python3-dev</code></pre><h2 id="create-bot-application">Create Bot Application</h2><p>Next you will create a new application and bot account on the <a href="https://discord.com/developers/applications">Discord Application Development Page</a>.</p><p>Create a new application then in the application menu click Bot and then Add a new Bot account.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cindr.org/content/images/2022/07/image-6.png" class="kg-image" alt="How to Create a Simple Discord Bot using Python" loading="lazy" width="350" height="298"><figcaption>Application Settings Menu</figcaption></figure><p>Once the bot account is created you will need to select the intents your Bot will need, you can change these later. But for your bot to respond to messages you should enable the <strong>Message Content Intent</strong>.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cindr.org/content/images/2022/07/image-7.png" class="kg-image" alt="How to Create a Simple Discord Bot using Python" loading="lazy" width="1413" height="1185" srcset="https://cindr.org/content/images/size/w600/2022/07/image-7.png 600w, https://cindr.org/content/images/size/w1000/2022/07/image-7.png 1000w, https://cindr.org/content/images/2022/07/image-7.png 1413w" sizes="(min-width: 720px) 720px"><figcaption>Bot Settings Page</figcaption></figure><p>Finally copy the bot token. You will need this to run your bot.</p><h2 id="add-bot-to-server">Add Bot to Server</h2><p>In the application settings menu click on <strong>OAuth2</strong> then <strong>URL Generator</strong>.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cindr.org/content/images/2022/07/image-8.png" class="kg-image" alt="How to Create a Simple Discord Bot using Python" loading="lazy" width="346" height="224"><figcaption>OAuth2 Settings</figcaption></figure><p>Under Scopes select <strong>Bot</strong> and copy the URL into your browser. You should get a popup allowing you to add your bot to your server.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cindr.org/content/images/2022/07/image-9.png" class="kg-image" alt="How to Create a Simple Discord Bot using Python" loading="lazy" width="1410" height="556" srcset="https://cindr.org/content/images/size/w600/2022/07/image-9.png 600w, https://cindr.org/content/images/size/w1000/2022/07/image-9.png 1000w, https://cindr.org/content/images/2022/07/image-9.png 1410w" sizes="(min-width: 720px) 720px"><figcaption>URL Generator</figcaption></figure><h1 id="create-a-simple-bot">Create a Simple Bot</h1><h2 id="basic-template">Basic Template</h2><p>This is a starter template from the <a href="https://discordpy.readthedocs.io/en/stable/intro.html">Discord.py Docs</a>. Fill in your bot token and then run the file to start your bot.</p><pre><code class="language-python">import discord

class MyClient(discord.Client):
    async def on_ready(self):
        print(f&apos;Logged on as {self.user}!&apos;)

    async def on_message(self, message):
        print(f&apos;Message from {message.author}: {message.content}&apos;)

intents = discord.Intents.default()
intents.message_content = True

client = MyClient(intents=intents)
client.run(&apos;TOKEN HERE&apos;)</code></pre><pre><code>python bot.py
</code></pre><p>You should have your bot online now.</p>]]></content:encoded></item><item><title><![CDATA[Add a discord user to your database (Login with Discord OAuth) in PHP]]></title><description><![CDATA[<p>This is a follow up to how to make a <a href="https://cindr.org/how-to-create-a-login-with-discord-button-in-php/">login with discord button in PHP</a> tutorial I made not too long ago.</p><p>Here, the objective is simple. Take that authenticated user and add them to our database. If they are already in there, just log them in.</p><p>Finally, we</p>]]></description><link>https://cindr.org/add-a-discord-user-to-your-database-login-with-discord-oauth-in-php/</link><guid isPermaLink="false">6354873e2635b20001363ca6</guid><dc:creator><![CDATA[Martin B]]></dc:creator><pubDate>Sun, 23 Oct 2022 01:02:10 GMT</pubDate><media:content url="https://cindr.org/content/images/2022/10/ghost_thumbnail.png" medium="image"/><content:encoded><![CDATA[<img src="https://cindr.org/content/images/2022/10/ghost_thumbnail.png" alt="Add a discord user to your database (Login with Discord OAuth) in PHP"><p>This is a follow up to how to make a <a href="https://cindr.org/how-to-create-a-login-with-discord-button-in-php/">login with discord button in PHP</a> tutorial I made not too long ago.</p><p>Here, the objective is simple. Take that authenticated user and add them to our database. If they are already in there, just log them in.</p><p>Finally, we will want to visualize our database, and output all of our joined users.</p><h1 id="video-tutorial">Video tutorial:</h1><p><a href="https://youtu.be/A9fhwOHZSdU">https://youtu.be/A9fhwOHZSdU</a></p><h1 id="setting-up-your-database">Setting up your database</h1><p>You need a way to access a mysql database. In my tutorial I have a locally hosted php server on WAMP, but you can use an external database, a locally hosted mysql server, WSL, etc. </p><p>In conjunction with WAMP, I&apos;m using phpmyadmin to access my database. Again, you can use whatever you want to access your database, phpmyadmin is just very common for beginners using php+mysql.</p><h3 id="step-1-create-the-database">Step 1: Create the database</h3><p>On the left side of the screen, hit new, and then navigate to the &quot;Database Name&quot; field. </p><figure class="kg-card kg-image-card"><img src="https://cindr.org/content/images/2022/10/Screenshot-2022-10-15-171619.png" class="kg-image" alt="Add a discord user to your database (Login with Discord OAuth) in PHP" loading="lazy" width="1629" height="722" srcset="https://cindr.org/content/images/size/w600/2022/10/Screenshot-2022-10-15-171619.png 600w, https://cindr.org/content/images/size/w1000/2022/10/Screenshot-2022-10-15-171619.png 1000w, https://cindr.org/content/images/size/w1600/2022/10/Screenshot-2022-10-15-171619.png 1600w, https://cindr.org/content/images/2022/10/Screenshot-2022-10-15-171619.png 1629w" sizes="(min-width: 720px) 720px"></figure><p>Enter in your database name. I will be naming it &quot;new_application&quot;</p><figure class="kg-card kg-image-card"><img src="https://cindr.org/content/images/2022/10/Screenshot-2022-10-15-171637-1.png" class="kg-image" alt="Add a discord user to your database (Login with Discord OAuth) in PHP" loading="lazy" width="644" height="324" srcset="https://cindr.org/content/images/size/w600/2022/10/Screenshot-2022-10-15-171637-1.png 600w, https://cindr.org/content/images/2022/10/Screenshot-2022-10-15-171637-1.png 644w"></figure><h3 id="step-2-create-a-table">Step 2: Create a table</h3><p>In your new database, on the first tab, create your table, enter your name, and select 4 for your number of columns</p><figure class="kg-card kg-image-card"><img src="https://cindr.org/content/images/2022/10/Screenshot-2022-10-15-171652.png" class="kg-image" alt="Add a discord user to your database (Login with Discord OAuth) in PHP" loading="lazy" width="831" height="426" srcset="https://cindr.org/content/images/size/w600/2022/10/Screenshot-2022-10-15-171652.png 600w, https://cindr.org/content/images/2022/10/Screenshot-2022-10-15-171652.png 831w" sizes="(min-width: 720px) 720px"></figure><h3 id="step-3-create-your-columns">Step 3: Create your columns</h3><figure class="kg-card kg-image-card"><img src="https://cindr.org/content/images/2022/10/Screenshot-2022-10-15-171736.png" class="kg-image" alt="Add a discord user to your database (Login with Discord OAuth) in PHP" loading="lazy" width="1885" height="575" srcset="https://cindr.org/content/images/size/w600/2022/10/Screenshot-2022-10-15-171736.png 600w, https://cindr.org/content/images/size/w1000/2022/10/Screenshot-2022-10-15-171736.png 1000w, https://cindr.org/content/images/size/w1600/2022/10/Screenshot-2022-10-15-171736.png 1600w, https://cindr.org/content/images/2022/10/Screenshot-2022-10-15-171736.png 1885w" sizes="(min-width: 720px) 720px"></figure><p>In your four columns, create an </p><p>id (INT, autoincrement, primary key); </p><p>discord_id (varchar(255)), </p><p>discord_avatar (varchar(255)), </p><p>and created_at (timestamp(CURRENT_TIME).</p><p>Your first column is your primary key. It will be automatically incremented by mySQL each time you create a new column. We don&apos;t have to worry about setting it.</p><p>You will supply the discord id given by our OAuth scheme, as seen in the previous tutorial.</p><p>Likewise, discord_avatar will be entered in.</p><p>Finally, created_at is just a timestamp marker of when we first inserted the user. Good for knowing when your users joined.</p><h1 id="connecting-to-your-database-in-php">Connecting to your database in PHP</h1><p>Now, head over to your project folder and create <strong>db.php</strong></p><p>Add the this basic connection code to connect to your database.</p><h3 id="add-connection-code-pdo">Add connection code (PDO)</h3><pre><code class="language-php">&lt;?php

$host = &quot;localhost&quot;;
$user = &quot;&quot;;
$pass = &quot;&quot;;
$db=&apos;new_application&apos;;

try {
  $pdo = new PDO(&quot;mysql:host=$host;dbname=$db&quot;, $user, $pass);
  $pdo-&gt;setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

  echo &quot;Connected successfully&quot;;
}
catch(PDOException $e){
  echo &quot;Connection failed: &quot; . $e-&gt;getMessage();
}

</code></pre><p>We need a username and a password to connect to our database</p><p>Let&apos;s create one in phpmyadmin.</p><p>Go to your database, and hit the privilege&apos;s tab</p><figure class="kg-card kg-image-card"><img src="https://cindr.org/content/images/2022/10/image-5.png" class="kg-image" alt="Add a discord user to your database (Login with Discord OAuth) in PHP" loading="lazy" width="1114" height="495" srcset="https://cindr.org/content/images/size/w600/2022/10/image-5.png 600w, https://cindr.org/content/images/size/w1000/2022/10/image-5.png 1000w, https://cindr.org/content/images/2022/10/image-5.png 1114w" sizes="(min-width: 720px) 720px"></figure><p>At the bottom of that screen, hit <strong>Add user account</strong></p><figure class="kg-card kg-image-card"><img src="https://cindr.org/content/images/2022/10/image-6.png" class="kg-image" alt="Add a discord user to your database (Login with Discord OAuth) in PHP" loading="lazy" width="2000" height="1279" srcset="https://cindr.org/content/images/size/w600/2022/10/image-6.png 600w, https://cindr.org/content/images/size/w1000/2022/10/image-6.png 1000w, https://cindr.org/content/images/size/w1600/2022/10/image-6.png 1600w, https://cindr.org/content/images/2022/10/image-6.png 2045w" sizes="(min-width: 720px) 720px"></figure><p>Create a username, hostname (% or any), password, and select grant all priviledges</p><figure class="kg-card kg-image-card"><img src="https://cindr.org/content/images/2022/10/image-7.png" class="kg-image" alt="Add a discord user to your database (Login with Discord OAuth) in PHP" loading="lazy" width="1112" height="692" srcset="https://cindr.org/content/images/size/w600/2022/10/image-7.png 600w, https://cindr.org/content/images/size/w1000/2022/10/image-7.png 1000w, https://cindr.org/content/images/2022/10/image-7.png 1112w" sizes="(min-width: 720px) 720px"></figure><p>Hit <strong>Go</strong>, and add those credentials to your db.php file.</p><pre><code class="language-php">&lt;?php

$host = &quot;localhost&quot;;
$user = &quot;devuser&quot;;
$pass = &quot;mysqlpassword&quot;;
$db=&apos;new_application&apos;;

try {
  $pdo = new PDO(&quot;mysql:host=$host;dbname=$db&quot;, $user, $pass);
  $pdo-&gt;setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

  echo &quot;Connected successfully&quot;;
}
catch(PDOException $e){
  echo &quot;Connection failed: &quot; . $e-&gt;getMessage();
}

</code></pre><p>Head over to your project, and see if your database connection is successful:</p><p><a href="http://localhost/login-with-discord/src/db.php">http://localhost/login-with-discord/src/db.php</a></p><h1 id="creating-functions-to-add-a-user-to-our-database">Creating functions to add a user to our database</h1><p>In your db.php file, test a basic mySQL insert statement:</p><pre><code class="language-php">&lt;?php

$host = &quot;localhost&quot;;
$user = &quot;devuser&quot;;
$pass = &quot;mysqlpassword&quot;;
$db=&apos;new_application&apos;;

try {
  $pdo = new PDO(&quot;mysql:host=$host;dbname=$db&quot;, $user, $pass);
  $pdo-&gt;setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

  echo &quot;Connected successfully&quot;;
}
catch(PDOException $e){
  echo &quot;Connection failed: &quot; . $e-&gt;getMessage();
}

function addUserToDatabase($pdo,$discord_id,$discord_avatar){
    $sql = &quot;INSERT INTO users (discord_id,discord_avatar) VALUES (:discord_id,:discord_avatar)&quot;;
    try {
        $stmt = $pdo-&gt;prepare($sql);
        $stmt-&gt;execute([
            &apos;discord_id&apos;=&gt;$discord_id,
            &apos;discord_avatar&apos;=&gt;$discord_avatar,
        ]);
        echo &apos;inserted successfully&apos;;
    } catch (Exception $e) {
        echo $e;
    }
}

addUserToDatabase($pdo,&apos;test&apos;,&apos;test&apos;);</code></pre><p>Execute db.php, and check your database to see if it worked:</p><figure class="kg-card kg-image-card"><img src="https://cindr.org/content/images/2022/10/image-8.png" class="kg-image" alt="Add a discord user to your database (Login with Discord OAuth) in PHP" loading="lazy" width="657" height="459" srcset="https://cindr.org/content/images/size/w600/2022/10/image-8.png 600w, https://cindr.org/content/images/2022/10/image-8.png 657w"></figure><p>Great, now let&apos;s retrieve a user by a discord id (to see if one exists)</p><p>Add this function to the same file:<br></p><pre><code class="language-php">function getUserFromDatabase($pdo,$discord_id){
    $sql = &quot;SELECT * FROM users WHERE discord_id=:discord_id&quot;;
    try {
        $stmt = $pdo-&gt;prepare($sql);
        $stmt-&gt;execute([
            &apos;discord_id&apos;=&gt;$discord_id,
        ]);
        $data = $stmt-&gt;fetch(PDO::FETCH_ASSOC);
        return $data;
    } catch (Exception $e) {
        echo $e;
    }
}

$discord_id = &apos;test&apos;;
$user_data = getUserFromDatabase($pdo,$discord_id);

if($user_data){
    echo &apos;user exists:&apos;;
    print_r($user_data);
}else{
    echo &apos;no user exists&apos;;
}</code></pre><p>We just added discord_id test, and so we will retrieve it to.</p><p>Finally, let&apos;s make a function that gets all discord users from our database:</p><pre><code class="language-php">function getAllUsersFromDatabase($pdo){
    $sql = &quot;SELECT * FROM users&quot;;
    try {
        $stmt = $pdo-&gt;prepare($sql);
        $stmt-&gt;execute();
        $data = $stmt-&gt;fetchAll(PDO::FETCH_ASSOC);
        return $data;
    } catch (Exception $e) {
        echo $e;
    }
}</code></pre><p>Let&apos;s output it on our users.php page</p><pre><code class="language-php">&lt;!doctype html&gt;
&lt;html&gt;
&lt;head&gt;
  &lt;meta charset=&quot;UTF-8&quot;&gt;
  &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&gt;
  &lt;link href=&quot;../dist/output.css&quot; rel=&quot;stylesheet&quot;&gt;
  &lt;link rel=&quot;stylesheet&quot; href=&quot;https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css&quot; integrity=&quot;sha512-KfkfwYDsLkIlwQp6LFnl8zNdLGxu9YAA1QvwINks4PhcElQSvqcyVLLD9aMhXd13uQjoXtEKNosOWaZqXgel0g==&quot; crossorigin=&quot;anonymous&quot; referrerpolicy=&quot;no-referrer&quot; /&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;div class=&quot;flex items-center justify-center h-screen bg-discord-gray text-white flex-col&quot;&gt;
        &lt;ul class=&quot;w-96 text-sm font-medium text-gray-900 bg-white rounded-lg border border-gray-200 dark:bg-gray-700 dark:border-gray-600 dark:text-white mt-6&quot;&gt;
            &lt;h3 class=&quot;text-xl font-bold ml-3 text-gray-300 uppercase py-2&quot;&gt;Users:&lt;/h3&gt;
        &lt;/ul&gt;
    &lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre><p>Now, add your php to the header to include our database functions file, as well as our get all users function.</p><p>Loop through it to add to html markup, and then print it in the html:<br></p><pre><code class="language-php">&lt;?php
include(&apos;db.php&apos;);

$all_users = getAllUsersFromDatabase($pdo);
$usersMarkup=&apos;&apos;;

foreach ($all_users as $key =&gt; $userData) {
    $usersMarkup.=&apos;&lt;li class=&quot;py-2 px-4 w-full rounded-t-lg border-b border-gray-200 dark:border-gray-600&quot;&gt;&apos;.$userData[&apos;discord_id&apos;].&apos;&lt;/li&gt;&apos;;
}

?&gt;
&lt;!doctype html&gt;
&lt;html&gt;
&lt;head&gt;
  &lt;meta charset=&quot;UTF-8&quot;&gt;
  &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&gt;
  &lt;link href=&quot;../dist/output.css&quot; rel=&quot;stylesheet&quot;&gt;
  &lt;link rel=&quot;stylesheet&quot; href=&quot;https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css&quot; integrity=&quot;sha512-KfkfwYDsLkIlwQp6LFnl8zNdLGxu9YAA1QvwINks4PhcElQSvqcyVLLD9aMhXd13uQjoXtEKNosOWaZqXgel0g==&quot; crossorigin=&quot;anonymous&quot; referrerpolicy=&quot;no-referrer&quot; /&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;div class=&quot;flex items-center justify-center h-screen bg-discord-gray text-white flex-col&quot;&gt;
        &lt;ul class=&quot;w-96 text-sm font-medium text-gray-900 bg-white rounded-lg border border-gray-200 dark:bg-gray-700 dark:border-gray-600 dark:text-white mt-6&quot;&gt;
            &lt;h3 class=&quot;text-xl font-bold ml-3 text-gray-300 uppercase py-2&quot;&gt;Users:&lt;/h3&gt;
            &lt;?php echo $usersMarkup;?&gt;
        &lt;/ul&gt;
    &lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre><p>We are now outputting users:</p><figure class="kg-card kg-image-card"><img src="https://cindr.org/content/images/2022/10/image-9.png" class="kg-image" alt="Add a discord user to your database (Login with Discord OAuth) in PHP" loading="lazy" width="1272" height="986" srcset="https://cindr.org/content/images/size/w600/2022/10/image-9.png 600w, https://cindr.org/content/images/size/w1000/2022/10/image-9.png 1000w, https://cindr.org/content/images/2022/10/image-9.png 1272w" sizes="(min-width: 720px) 720px"></figure><p>Finally, add the user via discord authentication, checking if the user exists in the database, and if not inserting them.</p><p>Good news is that we have the two functions for this, so let&apos;s head over to process-oauth</p><pre><code class="language-php">//Add this to the top of process-oauth.php
include(&apos;db.php&apos;);</code></pre><pre><code class="language-php">$userData = json_decode($result,true);

$user_data = getUserFromDatabase($pdo,$userData[&apos;id&apos;]);

if(!$user_data){
    addUserToDatabase($pdo,$userData[&apos;id&apos;],$userData[&apos;avatar&apos;]);
}


$_SESSION[&apos;logged_in&apos;] = true;
$_SESSION[&apos;userData&apos;] = [
    &apos;discord_id&apos;=&gt;$userData[&apos;id&apos;],
    &apos;name&apos;=&gt;$userData[&apos;username&apos;],
    &apos;avatar&apos;=&gt;$userData[&apos;avatar&apos;],
];
header(&quot;location: dashboard.php&quot;);
exit();</code></pre><p>Get the image to our user list in our markup of users.php:</p><pre><code class="language-php">$usersMarkup.=&apos;
&lt;li class=&quot;py-2 px-4 w-full rounded-t-lg border-b border-gray-200 dark:border-gray-600 flex  items-center&quot;&gt;
    &lt;img class=&quot;h-12 w-12 rounded-full mr-6&quot; src=&quot;https://cdn.discordapp.com/avatars/&apos;.$userData[&apos;discord_id&apos;].&apos;/&apos;.$userData[&apos;discord_avatar&apos;].&apos;.jpg&quot;/&gt;
    &apos;.$userData[&apos;discord_id&apos;].&apos;
&lt;/li&gt;&apos;;</code></pre>]]></content:encoded></item><item><title><![CDATA[How to join a user to a discord server, get a list of their servers (PHP, OAuth2.0)]]></title><description><![CDATA[<p>I&apos;ve been getting a lot of requests to get a list of a user&apos;s guilds on discord, and all you have to do is modify the original login with discord code a little bit.</p><h1 id="video">Video</h1><figure class="kg-card kg-embed-card"><iframe width="200" height="113" src="https://www.youtube.com/embed/JEZY7Aq6SQY?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen title="List User&apos;s Guilds/Servers, get user to join server on Discord OAuth using PHP"></iframe></figure><h1 id="written-guide">Written Guide</h1><p>Here are a list of changes</p><ul><li>Add scopes to</li></ul>]]></description><link>https://cindr.org/join-a-user-to-a-discord-server-get-a-list-of-their-servers/</link><guid isPermaLink="false">62ff98e82635b20001363c4d</guid><dc:creator><![CDATA[Martin B]]></dc:creator><pubDate>Fri, 19 Aug 2022 14:18:38 GMT</pubDate><media:content url="https://cindr.org/content/images/2022/08/join-guilds.png" medium="image"/><content:encoded><![CDATA[<img src="https://cindr.org/content/images/2022/08/join-guilds.png" alt="How to join a user to a discord server, get a list of their servers (PHP, OAuth2.0)"><p>I&apos;ve been getting a lot of requests to get a list of a user&apos;s guilds on discord, and all you have to do is modify the original login with discord code a little bit.</p><h1 id="video">Video</h1><figure class="kg-card kg-embed-card"><iframe width="200" height="113" src="https://www.youtube.com/embed/JEZY7Aq6SQY?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen title="List User&apos;s Guilds/Servers, get user to join server on Discord OAuth using PHP"></iframe></figure><h1 id="written-guide">Written Guide</h1><p>Here are a list of changes</p><ul><li>Add scopes to the URL</li><li>Add a joinGuild function</li><li>Add a getGuildsList function</li><li>Create a bot, add it to your server, and give it the right permissions</li><li>Markup the user&apos;s guilds</li></ul><p>So, if you haven&apos;t&apos; already, we will start at the last tutorial&apos;s end:</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://cindr.org/how-to-create-a-login-with-discord-button-in-php/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">How to create a login with Discord button in PHP</div><div class="kg-bookmark-description">Video TutorialCurrently, this tutorial is in video form only. We are working on a companionguide on the website! Feel free to comment on the video if you have any questions regarding thetutorial!</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://cindr.org/content/images/size/w256h256/2022/05/cindr-favicon.png" alt="How to join a user to a discord server, get a list of their servers (PHP, OAuth2.0)"><span class="kg-bookmark-author">Cindr.org</span><span class="kg-bookmark-publisher">Martin B</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://cindr.org/content/images/2022/05/login-with-discord-thumbnial.png" alt="How to join a user to a discord server, get a list of their servers (PHP, OAuth2.0)"></div></a></figure><h3 id="getting-a-new-url">Getting a new URL</h3><p>Generate yourself a new URL:</p><figure class="kg-card kg-image-card"><img src="https://cindr.org/content/images/2022/08/image-2.png" class="kg-image" alt="How to join a user to a discord server, get a list of their servers (PHP, OAuth2.0)" loading="lazy" width="1868" height="953" srcset="https://cindr.org/content/images/size/w600/2022/08/image-2.png 600w, https://cindr.org/content/images/size/w1000/2022/08/image-2.png 1000w, https://cindr.org/content/images/size/w1600/2022/08/image-2.png 1600w, https://cindr.org/content/images/2022/08/image-2.png 1868w" sizes="(min-width: 720px) 720px"></figure><p>Update your init-oauth.php file</p><figure class="kg-card kg-image-card"><img src="https://cindr.org/content/images/2022/08/image-3.png" class="kg-image" alt="How to join a user to a discord server, get a list of their servers (PHP, OAuth2.0)" loading="lazy" width="1620" height="537" srcset="https://cindr.org/content/images/size/w600/2022/08/image-3.png 600w, https://cindr.org/content/images/size/w1000/2022/08/image-3.png 1000w, https://cindr.org/content/images/size/w1600/2022/08/image-3.png 1600w, https://cindr.org/content/images/2022/08/image-3.png 1620w" sizes="(min-width: 720px) 720px"></figure><h2 id="handling-the-bot">Handling the bot</h2><h3 id="create-the-bot">Create the bot:</h3><figure class="kg-card kg-image-card"><img src="https://cindr.org/content/images/2022/08/image-4.png" class="kg-image" alt="How to join a user to a discord server, get a list of their servers (PHP, OAuth2.0)" loading="lazy" width="1891" height="1008" srcset="https://cindr.org/content/images/size/w600/2022/08/image-4.png 600w, https://cindr.org/content/images/size/w1000/2022/08/image-4.png 1000w, https://cindr.org/content/images/size/w1600/2022/08/image-4.png 1600w, https://cindr.org/content/images/2022/08/image-4.png 1891w" sizes="(min-width: 720px) 720px"></figure><p>Create the bot by heading to the <a href="https://discord.com/developers/applications/">https://discord.com/developers/applications/</a> and going to the same application that handles your OAuth. Create the bot.</p><h3 id="invite-the-bot-to-your-server">Invite the bot to your server:</h3><p>Go to OAuth, URL Generator, and select all of these scopes (this will give your bot permission to read the oauth data, and add the user via bot)</p><figure class="kg-card kg-image-card"><img src="https://cindr.org/content/images/2022/08/image-5.png" class="kg-image" alt="How to join a user to a discord server, get a list of their servers (PHP, OAuth2.0)" loading="lazy" width="2000" height="1214" srcset="https://cindr.org/content/images/size/w600/2022/08/image-5.png 600w, https://cindr.org/content/images/size/w1000/2022/08/image-5.png 1000w, https://cindr.org/content/images/size/w1600/2022/08/image-5.png 1600w, https://cindr.org/content/images/2022/08/image-5.png 2074w" sizes="(min-width: 720px) 720px"></figure><p>Finally, click on the link as the server owner, and add the bot to your server!</p><h3 id="adding-process-functions">Adding Process Functions</h3><p>Then, head on over to the proccess-oauth.php file and add the two new functions:</p><pre><code class="language-php">function addUserToGuild($discord_ID,$token,$guild_ID){
    $payload = [
        &apos;access_token&apos;=&gt;$token,
    ];

    $discord_api_url = &apos;https://discordapp.com/api/guilds/&apos;.$guild_ID.&apos;/members/&apos;.$discord_ID;

    $bot_token = &quot;YOUR BOT TOKEN (SAME AS APPLICATION)&quot;;
    $header = array(&quot;Authorization: Bot $bot_token&quot;, &quot;Content-Type: application/json&quot;);

    $ch = curl_init();
    //set the url, number of POST vars, POST data
    curl_setopt($ch, CURLOPT_HTTPHEADER,$header);
    curl_setopt($ch,CURLOPT_URL, $discord_api_url);
    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, &quot;PUT&quot;); //must be put for this method..
    curl_setopt($ch,CURLOPT_POSTFIELDS, json_encode($payload)); //must be a json body
    curl_setopt($ch,CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);

    $result = curl_exec($ch);
    
    if(!$result){
        echo curl_error($ch);
    }else{
        return true;
    }
}

function getUsersGuilds($auth_token){
    //url scheme /users/@me/guilds
    $discord_api_url = &quot;https://discordapp.com/api&quot;;
    $header = array(&quot;Authorization: Bearer $auth_token&quot;,&quot;Content-Type: application/x-www-form-urlencoded&quot;);
    $ch = curl_init();
    //set the url, number of POST vars, POST data
    curl_setopt($ch, CURLOPT_HTTPHEADER,$header);
    curl_setopt($ch,CURLOPT_URL, $discord_api_url.&apos;/users/@me/guilds&apos;);
    curl_setopt($ch,CURLOPT_POST, false);
    //curl_setopt($ch,CURLOPT_POSTFIELDS, $fields_string);
    curl_setopt($ch,CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
    $result = curl_exec($ch);
    $result = json_decode($result,true);
    return $result;
}</code></pre><p>The first function is a little bit tricky. We had to change the method to PUT using the CURLOPT_CUSTOMREQUEST parameter. Additionally, it insisted it wanted a json body so we encoded the token into that data format. </p><p>The getUsersGuilds is very similar to getting the user&apos;s data, however, this time it&apos;s /users/@me/guilds.</p><p>Now, let&apos;s actually use these functions in our code:</p><p>I&apos;m adding the user to my guild when I also fetch their user data, here is the area:</p><pre><code class="language-php"> $guild_ID = &apos;986726427950989372&apos;;
 $addUserToGuild = addUserToGuild($result[&apos;id&apos;],$access_token,$guild_ID);</code></pre><figure class="kg-card kg-image-card"><img src="https://cindr.org/content/images/2022/08/image.png" class="kg-image" alt="How to join a user to a discord server, get a list of their servers (PHP, OAuth2.0)" loading="lazy" width="828" height="314" srcset="https://cindr.org/content/images/size/w600/2022/08/image.png 600w, https://cindr.org/content/images/2022/08/image.png 828w" sizes="(min-width: 720px) 720px"></figure><p>Additionally, if you want to fetch their guild data, I will just append the function into my session variable:</p><pre><code class="language-php">$_SESSION[&apos;userData&apos;] = [
    &apos;discord_id&apos;=&gt;$userData[&apos;id&apos;],
    &apos;name&apos;=&gt;$userData[&apos;username&apos;],
    &apos;avatar&apos;=&gt;$userData[&apos;avatar&apos;],
    &apos;guilds&apos;=&gt;getUsersGuilds($access_token)
];</code></pre><figure class="kg-card kg-image-card"><img src="https://cindr.org/content/images/2022/08/image-1.png" class="kg-image" alt="How to join a user to a discord server, get a list of their servers (PHP, OAuth2.0)" loading="lazy" width="673" height="420" srcset="https://cindr.org/content/images/size/w600/2022/08/image-1.png 600w, https://cindr.org/content/images/2022/08/image-1.png 673w"></figure><p>Finally, markup your new guild data:</p><p>Add this to the head of the file;</p><pre><code class="language-php">$guilds = $_SESSION[&apos;userData&apos;][&apos;guilds&apos;];
$guildMarkup=&apos;&apos;;

foreach ($guilds as $key =&gt; $guildData) {
    $guildMarkup.=&apos;&lt;li class=&quot;py-2 px-4 w-full rounded-t-lg border-b border-gray-200 dark:border-gray-600&quot;&gt;&apos;.$guildData[&apos;name&apos;].&apos;&lt;/li&gt;&apos;;
}</code></pre><p>And this to your HTML body:</p><pre><code class="language-php">&lt;ul class=&quot;w-96 text-sm font-medium text-gray-900 bg-white rounded-lg border border-gray-200 dark:bg-gray-700 dark:border-gray-600 dark:text-white mt-6&quot;&gt;
    &lt;h3 class=&quot;text-xl font-bold ml-3 text-gray-300 uppercase py-2&quot;&gt;Guilds:&lt;/h3&gt;
    &lt;?php echo $guildMarkup;?&gt;
&lt;/ul&gt;</code></pre><p>Finally, update your css file to get some of those new tailwind classes:</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://github.com/mbouldo/login-with-discord-php/blob/main/dist/output.css"><div class="kg-bookmark-content"><div class="kg-bookmark-title">login-with-discord-php/output.css at main &#xB7; mbouldo/login-with-discord-php</div><div class="kg-bookmark-description">A simple login with Discord using PHP. Contribute to mbouldo/login-with-discord-php development by creating an account on GitHub.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://github.com/fluidicon.png" alt="How to join a user to a discord server, get a list of their servers (PHP, OAuth2.0)"><span class="kg-bookmark-author">GitHub</span><span class="kg-bookmark-publisher">mbouldo</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://opengraph.githubassets.com/637e82785089c13f9e38febb91efcd4c4b3378bc0e2d6dcb0543e9ada75fff09/mbouldo/login-with-discord-php" alt="How to join a user to a discord server, get a list of their servers (PHP, OAuth2.0)"></div></a></figure>]]></content:encoded></item><item><title><![CDATA[How to Host a Free Static Website with GitHub Pages]]></title><description><![CDATA[<figure class="kg-card kg-embed-card"><iframe width="200" height="113" src="https://www.youtube.com/embed/e5vd5KYrW8c?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen title="How to Host a Free Static Website using GitHub Pages"></iframe></figure><p>With GitHub Pages you can host a free static website. This is useful for simple sites such as personal blogs or portfolio sites. </p><p>The information for this guide was taken from the official GitHub Documentation located <a href="https://docs.github.com/en/pages">here</a>. If you prefer a more detailed explanation you can read it there however</p>]]></description><link>https://cindr.org/how-to/</link><guid isPermaLink="false">62a255e3e246ee00017e7500</guid><dc:creator><![CDATA[Idean]]></dc:creator><pubDate>Sun, 17 Jul 2022 01:40:12 GMT</pubDate><media:content url="https://cindr.org/content/images/2022/08/github_pages.png" medium="image"/><content:encoded><![CDATA[<figure class="kg-card kg-embed-card"><iframe width="200" height="113" src="https://www.youtube.com/embed/e5vd5KYrW8c?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen title="How to Host a Free Static Website using GitHub Pages"></iframe></figure><img src="https://cindr.org/content/images/2022/08/github_pages.png" alt="How to Host a Free Static Website with GitHub Pages"><p>With GitHub Pages you can host a free static website. This is useful for simple sites such as personal blogs or portfolio sites. </p><p>The information for this guide was taken from the official GitHub Documentation located <a href="https://docs.github.com/en/pages">here</a>. If you prefer a more detailed explanation you can read it there however it can be a bit confusing and I provide examples for some of the parts that caused me problems such as setting up the DNS records.</p><h1 id="creating-the-repository">Creating the Repository</h1><p>The first step is to create a new <strong>public</strong> repository with the following name. You can do that using this link <a href="https://github.com/new">https://github.com/new</a>. Make sure the entire repo name is <strong>lowercase</strong>.</p><pre><code>&lt;user&gt;.github.io</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cindr.org/content/images/2022/06/image-5.png" class="kg-image" alt="How to Host a Free Static Website with GitHub Pages" loading="lazy" width="1903" height="781" srcset="https://cindr.org/content/images/size/w600/2022/06/image-5.png 600w, https://cindr.org/content/images/size/w1000/2022/06/image-5.png 1000w, https://cindr.org/content/images/size/w1600/2022/06/image-5.png 1600w, https://cindr.org/content/images/2022/06/image-5.png 1903w" sizes="(min-width: 720px) 720px"><figcaption>Create a new GitHub Repository for our static site.</figcaption></figure><p>You can change the remaining settings however you like.</p><h1 id="creating-the-website">Creating the Website</h1><p>To test the site I added a basic index.html template to the repository.</p><pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
&lt;head&gt;
    &lt;meta charset=&quot;UTF-8&quot;&gt;
    &lt;meta http-equiv=&quot;X-UA-Compatible&quot; content=&quot;IE=edge&quot;&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&gt;
    &lt;title&gt;Document&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
    Test Page
&lt;/body&gt;
&lt;/html&gt;</code></pre><p>Now visiting https://&lt;user&gt;.github.io should show you the index page.</p><h1 id="using-a-custom-domain-optional">Using a Custom Domain (Optional)</h1><h2 id="dns-settings">DNS Settings</h2><p>If you wanted to use a custom domain with your site you will need to create DNS records pointing to your repository.</p><p>These are my records I created using Google Domains</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cindr.org/content/images/2022/06/image-6.png" class="kg-image" alt="How to Host a Free Static Website with GitHub Pages" loading="lazy" width="1534" height="1112" srcset="https://cindr.org/content/images/size/w600/2022/06/image-6.png 600w, https://cindr.org/content/images/size/w1000/2022/06/image-6.png 1000w, https://cindr.org/content/images/2022/06/image-6.png 1534w" sizes="(min-width: 720px) 720px"><figcaption>DNS Records</figcaption></figure><p><strong>A</strong> Records</p><pre><code>185.199.108.153
185.199.109.153
185.199.110.153
185.199.111.153</code></pre><p><strong>AAAA</strong> Records</p><pre><code>2606:50c0:8000::153
2606:50c0:8001::153
2606:50c0:8002::153
2606:50c0:8003::153</code></pre><p>CNAME Record</p><pre><code>&lt;user&gt;.github.io</code></pre><p>You can find more details regarding this topic on the GitHub docs located <a href="https://docs.github.com/en/pages/configuring-a-custom-domain-for-your-github-pages-site/managing-a-custom-domain-for-your-github-pages-site">here</a>.</p><h2 id="change-repository-settings">Change Repository Settings</h2><p>After creating the DNS records go back to your repository and go to <strong>Settings &gt; Pages</strong>. You will want to enter your domain in the <strong>Custom domain</strong> field and click save.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cindr.org/content/images/2022/06/image-7.png" class="kg-image" alt="How to Host a Free Static Website with GitHub Pages" loading="lazy" width="1905" height="977" srcset="https://cindr.org/content/images/size/w600/2022/06/image-7.png 600w, https://cindr.org/content/images/size/w1000/2022/06/image-7.png 1000w, https://cindr.org/content/images/size/w1600/2022/06/image-7.png 1600w, https://cindr.org/content/images/2022/06/image-7.png 1905w" sizes="(min-width: 720px) 720px"><figcaption>Repository Pages Settings</figcaption></figure><p>After clicking save it will perform a DNS check to ensure your settings are correct. It can take up to an hour for the DNS records to update but for me it happened within a few minutes. </p><p>If you are unable to enable <strong>Enforce HTTPS</strong> you may need to wait for a few minutes then refresh the page.</p><h1 id="adding-a-theme-optional">Adding a Theme (Optional)</h1><p>You can add a premade Jekyll theme to your repository from the Pages settings located at <strong>Settings &gt; Pages.</strong></p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cindr.org/content/images/2022/06/image-8.png" class="kg-image" alt="How to Host a Free Static Website with GitHub Pages" loading="lazy" width="847" height="194" srcset="https://cindr.org/content/images/size/w600/2022/06/image-8.png 600w, https://cindr.org/content/images/2022/06/image-8.png 847w" sizes="(min-width: 720px) 720px"><figcaption>GitHub Pages Theme Chooser</figcaption></figure><p>This will add a basic theme to all Markdown files in the repository. For details on how to customize the layout of these pages refer to the <a href="https://jekyllrb.com/docs/layouts/">Jekyll Documentation</a>.</p><p>To add the theme to our <strong>index.html</strong> page you need to add the Jekyll Front Matter to the top of the file.</p><pre><code class="language-yml">---
layout: default
title: Home Page
---</code></pre><p>The index page should now have the theme applied.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cindr.org/content/images/2022/06/image-9.png" class="kg-image" alt="How to Host a Free Static Website with GitHub Pages" loading="lazy" width="1918" height="979" srcset="https://cindr.org/content/images/size/w600/2022/06/image-9.png 600w, https://cindr.org/content/images/size/w1000/2022/06/image-9.png 1000w, https://cindr.org/content/images/size/w1600/2022/06/image-9.png 1600w, https://cindr.org/content/images/2022/06/image-9.png 1918w" sizes="(min-width: 720px) 720px"><figcaption>Index Page with Theme Applied</figcaption></figure><h1 id="conclusion">Conclusion</h1><p>Here are some other useful guides you can use to create your website.</p><!--kg-card-begin: markdown--><ul>
<li>Using Jekyll with GitHub Pages (Coming Soon)</li>
<li>Using a Custom Jekyll Theme with GitHub Pages (Coming Soon)</li>
<li><a href="https://docs.github.com/en/pages">Official GitHub Pages Documentation</a></li>
<li><a href="https://docs.github.com/en/pages/setting-up-a-github-pages-site-with-jekyll/about-github-pages-and-jekyll">Official GitHub Pages Jekyll Documentation</a></li>
</ul>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Add Events to a Mapbox map via PHP]]></title><description><![CDATA[<p>Adding a map to your application is very easy to do these days. You might use the more popular google maps, but Mapbox makes this process really simple. In order to create a map, you will use Javascript, but to save and provide data for the map we will use</p>]]></description><link>https://cindr.org/add-events-to-a-mapbox-map-via-php/</link><guid isPermaLink="false">62c0c04d2635b20001363a25</guid><dc:creator><![CDATA[Martin B]]></dc:creator><pubDate>Sat, 02 Jul 2022 22:34:08 GMT</pubDate><media:content url="https://cindr.org/content/images/2022/07/Screenshot-2022-07-02-173048.png" medium="image"/><content:encoded><![CDATA[<img src="https://cindr.org/content/images/2022/07/Screenshot-2022-07-02-173048.png" alt="Add Events to a Mapbox map via PHP"><p>Adding a map to your application is very easy to do these days. You might use the more popular google maps, but Mapbox makes this process really simple. In order to create a map, you will use Javascript, but to save and provide data for the map we will use php.</p><h2 id="video-guide">Video Guide:</h2><figure class="kg-card kg-embed-card"><iframe width="200" height="113" src="https://www.youtube.com/embed/yiqV9tDdCVc?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen title="Add an event to a map using Mapbox and PHP"></iframe></figure><h2 id="source-code">Source Code:</h2><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://github.com/mbouldo/mapbox-events-php"><div class="kg-bookmark-content"><div class="kg-bookmark-title">GitHub - mbouldo/mapbox-events-php: Add events to a map via mapbox &amp; retrieve data async via JS and PHP</div><div class="kg-bookmark-description">Add events to a map via mapbox &amp; retrieve data async via JS and PHP - GitHub - mbouldo/mapbox-events-php: Add events to a map via mapbox &amp; retrieve data async via JS and PHP</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://github.com/fluidicon.png" alt="Add Events to a Mapbox map via PHP"><span class="kg-bookmark-author">GitHub</span><span class="kg-bookmark-publisher">mbouldo</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://opengraph.githubassets.com/08b29f562fb5774406aaa5378bdc00610efc366e03f0a66388597b6f3a9b6cd0/mbouldo/mapbox-events-php" alt="Add Events to a Mapbox map via PHP"></div></a></figure><h2 id="helpful-links">Helpful Links:</h2><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.mapbox.com/maps"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Maps | Mapbox</div><div class="kg-bookmark-description">Unparalleled speed and customization to visualize your world.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://assets.website-files.com/5e832e12eb7ca02ee9064d42/6017e6f3638599d888fa44be_mapbox_favicon_256x256.png" alt="Add Events to a Mapbox map via PHP"><span class="kg-bookmark-author">Mapbox</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://assets.website-files.com/5e832e12eb7ca02ee9064d42/5f7ecf2e278db24a5f5bf419_Maps.jpg" alt="Add Events to a Mapbox map via PHP"></div></a></figure><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://docs.mapbox.com/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Documentation</div><div class="kg-bookmark-description">Examples, tutorials, and API references to help you start building with Mapbox.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://static-assets.mapbox.com/branding/favicon/v1/apple-touch-icon.png?v=gAd4JjrGWl" alt="Add Events to a Mapbox map via PHP"><span class="kg-bookmark-author">Mapbox</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://static-assets.mapbox.com/branding/social/social-1200x630.v2.jpg" alt="Add Events to a Mapbox map via PHP"></div></a></figure><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://docs.mapbox.com/mapbox-gl-js/guides/install/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Installation | Mapbox GL JS</div><div class="kg-bookmark-description">Get started with Mapbox GL JS.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://static-assets.mapbox.com/branding/favicon/v1/apple-touch-icon.png?v=gAd4JjrGWl" alt="Add Events to a Mapbox map via PHP"><span class="kg-bookmark-author">Mapbox</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://static-assets.mapbox.com/branding/social/social-1200x630.v2.jpg" alt="Add Events to a Mapbox map via PHP"></div></a></figure><h1 id="written-guide">Written Guide:</h1><h2 id="basic-pages-and-styles">Basic Pages, and styles</h2><h3 id="basic-html">Basic HTML</h3><pre><code class="language-html">&lt;div class=&quot;flex font-sans&quot;&gt;
    &lt;!-- SIDEBAR --&gt;
    &lt;div class=&quot;w-1/5 bg-gray-900 h-screen&quot;&gt;
        &lt;!-- LOGO --&gt;
        &lt;div class=&quot;flex justify-center pt-8 pb-8 border-b border-b-white&quot;&gt;
            &lt;img src=&quot;../dist/mapbox-logo-white.svg&quot; class=&quot;h-14&quot; /&gt;
        &lt;/div&gt;

        &lt;!-- HEADING --&gt;
        &lt;h3 class=&quot;text-white font-bold  text-center text-3xl mt-8 flex items-center w-full justify-center&quot;&gt;
            &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; class=&quot;h-10 w-10 mr-1&quot; fill=&quot;none&quot; viewBox=&quot;0 0 24 24&quot; stroke=&quot;currentColor&quot;
                stroke-width=&quot;2&quot;&gt;
                &lt;path stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; d=&quot;M12 6v6m0 0v6m0-6h6m-6 0H6&quot; /&gt;
            &lt;/svg&gt;
            Add an Event
        &lt;/h3&gt;

        &lt;!-- ADD EVENT FORM --&gt;
        &lt;div class=&quot;mb-6 w-5/6 mx-auto mt-12&quot;&gt;
            &lt;label for=&quot;eventName&quot; class=&quot;block mb-2 text-sm font-medium text-gray-900 dark:text-gray-300&quot;&gt;Event Name&lt;/label&gt;
            &lt;input type=&quot;text&quot; id=&quot;eventName&quot; class=&quot;input-field&quot; placeholder=&quot;DC Event&quot; required&gt;
        &lt;/div&gt;

        &lt;div class=&quot;mb-6 w-5/6 mx-auto mt-6&quot;&gt;
            &lt;label for=&quot;eventDescription&quot; class=&quot;block mb-2 text-sm font-medium text-gray-900 dark:text-gray-300&quot;&gt;Event
                Description&lt;/label&gt;
            &lt;input type=&quot;text&quot; id=&quot;eventDescription&quot; class=&quot;input-field&quot; placeholder=&quot;There will be very cool refreshments&quot;
                required&gt;
        &lt;/div&gt;
        
        &lt;div class=&quot;mb-6 w-5/6 mx-auto mt-6&quot;&gt;
            &lt;label for=&quot;geocoder&quot; class=&quot;block mb-2 text-sm font-medium text-gray-900 dark:text-gray-300&quot;&gt;Event Address&lt;/label&gt;
            &lt;div id=&quot;geocoder&quot;&gt;&lt;/div&gt;
        &lt;/div&gt;
        
        &lt;div class=&quot;w-5/6 mx-auto flex justify-end&quot;&gt;
            &lt;button type=&quot;button&quot; class=&quot;submit-button&quot; onclick=&quot;addEvent()&quot;&gt;Add Event&lt;/button&gt;
        &lt;/div&gt;
    &lt;/div&gt;
    &lt;!-- MAP --&gt;
    &lt;div class=&quot;h-screen w-full&quot; id=&quot;map&quot;&gt;&lt;/div&gt;
&lt;/div&gt;</code></pre><h3 id="styles">Styles</h3><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://github.com/mbouldo/mapbox-events-php/blob/main/dist/output.css"><div class="kg-bookmark-content"><div class="kg-bookmark-title">mapbox-events-php/output.css at main &#xB7; mbouldo/mapbox-events-php</div><div class="kg-bookmark-description">Add events to a map via mapbox &amp; retrieve data async via JS and PHP - mapbox-events-php/output.css at main &#xB7; mbouldo/mapbox-events-php</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://github.com/fluidicon.png" alt="Add Events to a Mapbox map via PHP"><span class="kg-bookmark-author">GitHub</span><span class="kg-bookmark-publisher">mbouldo</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://opengraph.githubassets.com/08b29f562fb5774406aaa5378bdc00610efc366e03f0a66388597b6f3a9b6cd0/mbouldo/mapbox-events-php" alt="Add Events to a Mapbox map via PHP"></div></a></figure><h3 id="header-dependencies">Header Dependencies</h3><pre><code class="language-html">&lt;link rel=&quot;preconnect&quot; href=&quot;https://fonts.googleapis.com&quot;&gt;
&lt;link rel=&quot;preconnect&quot; href=&quot;https://fonts.gstatic.com&quot; crossorigin&gt;
&lt;link href=&quot;https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800;900&amp;family=Poppins:wght@400;500;600;700;900&amp;display=swap&quot; rel=&quot;stylesheet&quot;&gt;
&lt;link rel=&quot;stylesheet&quot; href=&quot;https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-geocoder/v5.0.0/mapbox-gl-geocoder.css&quot; type=&quot;text/css&quot;&gt;
&lt;link href=&quot;../dist/output.css&quot; rel=&quot;stylesheet&quot;&gt;</code></pre><h3 id="mapbox-jquery-dependencies">Mapbox, JQuery Dependencies</h3><pre><code class="language-html">&lt;script src=&quot;https://code.jquery.com/jquery-3.6.0.min.js&quot; integrity=&quot;sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=&quot; crossorigin=&quot;anonymous&quot;&gt;&lt;/script&gt;
&lt;script src=&apos;https://api.mapbox.com/mapbox-gl-js/v2.9.1/mapbox-gl.js&apos;&gt;&lt;/script&gt;
&lt;link href=&apos;https://api.mapbox.com/mapbox-gl-js/v2.9.1/mapbox-gl.css&apos; rel=&apos;stylesheet&apos; /&gt;
&lt;script src=&quot;https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-geocoder/v5.0.0/mapbox-gl-geocoder.min.js&quot;&gt;&lt;/script&gt;</code></pre><h3 id="initialize-your-map-in-a-script-tag">Initialize Your Map (In a script tag)</h3><pre><code class="language-js">mapboxgl.accessToken = &apos;YOUR_MAPBOX_TOKEN_HERE&apos;;

var map = new mapboxgl.Map({
    container: &apos;map&apos;,
    style: &apos;mapbox://styles/mapbox/streets-v11&apos;,
    center: [-77.04, 38.907],
    zoom: 11.15
});</code></pre><h2 id="get-events-data-add-to-map">Get Events Data &amp; Add to Map</h2><h3 id="load-an-icons-layer-onto-your-map">Load an icons layer onto your map</h3><pre><code class="language-js">map.on(&apos;load&apos;, function () {
    //place object we will add our events to
    map.addSource(&apos;places&apos;,{
        &apos;type&apos;: &apos;geojson&apos;,
        &apos;data&apos;: {
            &apos;type&apos;: &apos;FeatureCollection&apos;,
            &apos;features&apos;: []
        }
    });
    //add place object to map
    map.addLayer({
        &apos;id&apos;: &apos;places&apos;,
        &apos;type&apos;: &apos;symbol&apos;,
        &apos;source&apos;: &apos;places&apos;,
        &apos;layout&apos;: {
            &apos;icon-image&apos;: &apos;{icon}&apos;,
            &apos;icon-allow-overlap&apos;: true
        }
    });

    //Handle popups
    map.on(&apos;click&apos;, &apos;places&apos;, (e) =&gt; {
        const coordinates = e.features[0].geometry.coordinates.slice();
        const description = e.features[0].properties.description;
        while (Math.abs(e.lngLat.lng - coordinates[0]) &gt; 180) {
            coordinates[0] += e.lngLat.lng &gt; coordinates[0] ? 360 : -360;
    }
    new mapboxgl.Popup()
        .setLngLat(coordinates)
        .setHTML(description)
        .addTo(map);
    });

    //Handle pointer styles
    map.on(&apos;mouseenter&apos;, &apos;places&apos;, () =&gt; {
        map.getCanvas().style.cursor = &apos;pointer&apos;;
    });
    map.on(&apos;mouseleave&apos;, &apos;places&apos;, () =&gt; {
        map.getCanvas().style.cursor = &apos;&apos;;
    });

    //get our data from php function
    //getAllEvents();
});</code></pre><h3 id="async-get-events-data-from-php">Async get events data from PHP</h3><pre><code class="language-js">function getAllEvents(){
    $.ajax({
        url: &quot;../api/getAllEvents.php&quot;,
        contentType: &quot;application/json&quot;,
        dataType: &quot;json&quot;,
        success: function (eventData) {
            console.log(eventData)
            map.getSource(&apos;places&apos;).setData({
                    &apos;type&apos;: &apos;FeatureCollection&apos;,
                    &apos;features&apos;: eventData
            });
        },
        error: function (e) {
            console.log(e);
        }
    });
}</code></pre><h3 id="create-a-new-database">Create a new database</h3><figure class="kg-card kg-image-card"><img src="https://cindr.org/content/images/2022/07/image.png" class="kg-image" alt="Add Events to a Mapbox map via PHP" loading="lazy" width="678" height="258" srcset="https://cindr.org/content/images/size/w600/2022/07/image.png 600w, https://cindr.org/content/images/2022/07/image.png 678w"></figure><h3 id="add-an-events-table">Add an events table</h3><figure class="kg-card kg-image-card"><img src="https://cindr.org/content/images/2022/07/image-1.png" class="kg-image" alt="Add Events to a Mapbox map via PHP" loading="lazy" width="769" height="169" srcset="https://cindr.org/content/images/size/w600/2022/07/image-1.png 600w, https://cindr.org/content/images/2022/07/image-1.png 769w" sizes="(min-width: 720px) 720px"></figure><h3 id="create-your-id-event-lat-lng-columns-name-and-description">Create your id, event, lat, lng columns, name, and description</h3><figure class="kg-card kg-image-card"><img src="https://cindr.org/content/images/2022/07/image-2.png" class="kg-image" alt="Add Events to a Mapbox map via PHP" loading="lazy" width="1654" height="359" srcset="https://cindr.org/content/images/size/w600/2022/07/image-2.png 600w, https://cindr.org/content/images/size/w1000/2022/07/image-2.png 1000w, https://cindr.org/content/images/size/w1600/2022/07/image-2.png 1600w, https://cindr.org/content/images/2022/07/image-2.png 1654w" sizes="(min-width: 720px) 720px"></figure><h3 id="your-table-should-look-like-this">Your table should look like this:</h3><figure class="kg-card kg-image-card"><img src="https://cindr.org/content/images/2022/07/image-3.png" class="kg-image" alt="Add Events to a Mapbox map via PHP" loading="lazy" width="930" height="247" srcset="https://cindr.org/content/images/size/w600/2022/07/image-3.png 600w, https://cindr.org/content/images/2022/07/image-3.png 930w" sizes="(min-width: 720px) 720px"></figure><h3 id="connect-your-php-file-that-handles-events-to-your-db">Connect your PHP file that handles events to your DB</h3><pre><code class="language-php">&lt;?php

$db = &quot;mapboxevents&quot;;
$host = &quot;localhost&quot;;
$user = &apos;USERNAME&apos;;
$pass = &apos;PASSWORD&apos;;

//PDO Connection
try {
    $pdo = new PDO(&quot;mysql:host=$host;dbname=$db&quot;, $user, $pass);
    $pdo-&gt;setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    //echo &quot;Connected successfully&quot;;
}
catch(PDOException $e){
    //echo &quot;Connection failed: &quot; . $e-&gt;getMessage();
}

function p($arr){
    echo &quot;&lt;pre&gt;&quot;;
        print_r($arr);
    echo &quot;&lt;/pre&gt;&quot;;
}</code></pre><h3 id="get-event-data-from-your-events-table">Get event data from your events table</h3><pre><code class="language-php">$sql = &quot;SELECT * FROM events&quot;;

try {
    $stmt = $pdo-&gt;prepare($sql);
    $stmt-&gt;execute();
    $data = $stmt-&gt;fetchAll(PDO::FETCH_ASSOC);

} catch (Exception $e) {
    die($e);
}</code></pre><h3 id="morph-your-data-from-mysql-into-json-mapbox-can-use">Morph your $data from mySQL Into json Mapbox can use</h3><pre><code class="language-php">foreach ($data as $key =&gt; $eventData) {
    $returnData[] = [
        &apos;type&apos; =&gt; &apos;Feature&apos;.$eventData[&apos;id&apos;],
        &apos;properties&apos; =&gt; [
            &apos;description&apos; =&gt; &apos;&lt;strong&gt;&apos;.$eventData[&apos;name&apos;].&apos;&lt;/strong&gt;&lt;p&gt;&apos;.$eventData[&apos;description&apos;].&apos;&lt;/p&gt;&apos;,
            &apos;icon&apos; =&gt; &apos;rocket-15&apos;
        ],
        &apos;geometry&apos; =&gt; [
            &apos;type&apos; =&gt; &apos;Point&apos;,
            &apos;coordinates&apos; =&gt; [$eventData[&apos;lat&apos;], $eventData[&apos;lng&apos;]]
        ]
    ];
}</code></pre><h3 id="set-your-headers-to-support-json-and-echo-out-your-json">Set your headers to support json, and echo out your json</h3><pre><code class="language-php">//top of file
header(&apos;Content-Type: application/json; charset=utf-8&apos;);
include(&apos;db.php&apos;);

//bottom of file
echo json_encode($returnData);</code></pre><h3 id="test-your-first-event-by-adding-it-into-your-mysql">Test your first event, by adding it into your mySQL</h3><pre><code class="language-sql">INSERT INTO `events` (`id`, `name`, `description`, `lat`, `lng`) VALUES (NULL, &apos;Manual mySQL&apos;, &apos;Test mySQL event&apos;, &apos;-77.0877945&apos;, &apos;38.937867&apos;);</code></pre><figure class="kg-card kg-image-card"><img src="https://cindr.org/content/images/2022/07/image-4.png" class="kg-image" alt="Add Events to a Mapbox map via PHP" loading="lazy" width="614" height="573" srcset="https://cindr.org/content/images/size/w600/2022/07/image-4.png 600w, https://cindr.org/content/images/2022/07/image-4.png 614w"></figure><h2 id="add-events-to-your-database">Add events to your database:</h2><p>Your php file will contain a simple PDO sql statement that will insert all of the posted variables, including <strong>name, description, lat, and lng</strong></p><h3 id="php-process-file-that-will-add-to-db">PHP Process File that will add to DB</h3><pre><code class="language-php">&lt;?php
// api/createEvent.php
include(&apos;db.php&apos;);

if(isset($_POST[&apos;name&apos;])){
    $sql = &quot;INSERT into events (name,description,lat,lng) VALUES (:name,:description,:lat,:lng)&quot;;
    try {
        $stmt = $pdo-&gt;prepare($sql);
        $stmt-&gt;execute([
            &apos;name&apos;=&gt;$_POST[&apos;name&apos;],
            &apos;description&apos;=&gt;$_POST[&apos;description&apos;],
            &apos;lat&apos;=&gt;$_POST[&apos;lat&apos;],
            &apos;lng&apos;=&gt;$_POST[&apos;lng&apos;],
        ]);

        echo json_encode(&apos;success&apos;);
    
    } catch (Exception $e) {
        die($e);
    }
}
</code></pre><h3 id="async-javascript-file-to-call-your-api-file">Async JavaScript file to call your API file</h3><pre><code class="language-js">function addEvent(){
    $.ajax({
        url: &quot;../api/createEvent.php&quot;,
        type:&apos;POST&apos;,
        data:postObj,
        dataType: &quot;json&quot;,
        success: function (resp) {
            
        },
        error: function (e) {
            console.log(e);
        }
    });
}</code></pre><h3 id="initialize-your-geocoder-to-get-lat-lng-data">Initialize Your Geocoder to get lat, lng data</h3><pre><code class="language-js">const geocoder = new MapboxGeocoder({
    accessToken: mapboxgl.accessToken,
});

geocoder.addTo(&apos;#geocoder&apos;);

var geocoderResult = {};
geocoder.on(&apos;result&apos;, (e) =&gt; {
    geocoderResult = e.result, null, 2;
});

// Clear results container when search is cleared.
geocoder.on(&apos;clear&apos;, () =&gt; {
    geocoderResult = {};
});
</code></pre><h3 id="validate-if-geocoder-is-set-set-postdata">Validate if geocoder is set &amp; set postData</h3><pre><code class="language-js">    if(geocoderResult=={}){
        return false;
    }
    var postObj = {
        name:$(&quot;#eventName&quot;).val(),
        description:$(&quot;#eventDescription&quot;).val(),
        lat:geocoderResult.center[0],
        lng:geocoderResult.center[1],
    }</code></pre><h3 id="handle-success-when-event-is-created">Handle success when event is created</h3><pre><code class="language-js">//reset form &amp; get new data
$(&quot;#eventName&quot;).val(&apos;&apos;);
$(&quot;#eventDescription&quot;).val(&apos;&apos;);
geocoder.clear();
getAllEvents();</code></pre>]]></content:encoded></item><item><title><![CDATA[How Create a Windows 11 Virtual Machine using Hyper-V]]></title><description><![CDATA[<h1 id="video-guide">Video Guide</h1><figure class="kg-card kg-embed-card"><iframe width="200" height="113" src="https://www.youtube.com/embed/jOQlTIrAgjY?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen title="Create Windows 11 Virtual Machine in Hyper-V"></iframe></figure><h1 id="enable-hyper-v">Enable Hyper-V</h1><h2 id="system-requirements">System Requirements</h2><!--kg-card-begin: markdown--><ul>
<li>Windows 10 Pro</li>
<li>A 64-bit processor</li>
<li>At least 4 GB of RAM</li>
<li>Virtualization support turned on in the BIOS or UEFI</li>
</ul>
<!--kg-card-end: markdown--><p>You can check if you meet the requirements by running this command in PowerShell or command prompt.</p><pre><code class="language-cmd">Systeminfo.exe</code></pre><figure class="kg-card kg-code-card"><pre><code>Hyper-V Requirements:      VM Monitor</code></pre></figure>]]></description><link>https://cindr.org/how-to-install-windows-11-virtual-machine-on-windows-10-using-hyper-v/</link><guid isPermaLink="false">62816606cc55a9000135937e</guid><dc:creator><![CDATA[Idean]]></dc:creator><pubDate>Tue, 07 Jun 2022 17:16:56 GMT</pubDate><media:content url="https://cindr.org/content/images/2022/05/windows-11.webp" medium="image"/><content:encoded><![CDATA[<h1 id="video-guide">Video Guide</h1><figure class="kg-card kg-embed-card"><iframe width="200" height="113" src="https://www.youtube.com/embed/jOQlTIrAgjY?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen title="Create Windows 11 Virtual Machine in Hyper-V"></iframe></figure><h1 id="enable-hyper-v">Enable Hyper-V</h1><h2 id="system-requirements">System Requirements</h2><!--kg-card-begin: markdown--><ul>
<li>Windows 10 Pro</li>
<li>A 64-bit processor</li>
<li>At least 4 GB of RAM</li>
<li>Virtualization support turned on in the BIOS or UEFI</li>
</ul>
<!--kg-card-end: markdown--><img src="https://cindr.org/content/images/2022/05/windows-11.webp" alt="How Create a Windows 11 Virtual Machine using Hyper-V"><p>You can check if you meet the requirements by running this command in PowerShell or command prompt.</p><pre><code class="language-cmd">Systeminfo.exe</code></pre><figure class="kg-card kg-code-card"><pre><code>Hyper-V Requirements:      VM Monitor Mode Extensions: Yes
                           Virtualization Enabled In Firmware: Yes
                           Second Level Address Translation: Yes
                           Data Execution Prevention Available: Yes</code></pre><figcaption>Expected Result</figcaption></figure><h2 id="enable-virtualization-in-bios">Enable Virtualization in Bios</h2><p>Look for a setting called <strong>Intel Virtualization Technology (Intel VT) or AMD Virtualization technology &#xA0;(AMD-V). After enabling you should be able to turn on Hyper-V.</strong></p><p>This is usually located in the &#xA0;<strong>advanced settings</strong> under <strong>CPU</strong>. Some motherboards will have you in advanced mode automatically.<br></p><h2 id="turn-on-hyper-v">Turn on Hyper-V</h2><p>The easiest way to enable Hyper-V is to search for</p><pre><code>Turn Windows features on or off</code></pre><p>in the search bar and then tick the check box next to Hyper-V. You will need to reboot.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cindr.org/content/images/2022/05/features-1.png" class="kg-image" alt="How Create a Windows 11 Virtual Machine using Hyper-V" loading="lazy" width="784" height="537" srcset="https://cindr.org/content/images/size/w600/2022/05/features-1.png 600w, https://cindr.org/content/images/2022/05/features-1.png 784w" sizes="(min-width: 720px) 720px"><figcaption>Search for the Windows Features Menu</figcaption></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cindr.org/content/images/2022/05/windows-features.png" class="kg-image" alt="How Create a Windows 11 Virtual Machine using Hyper-V" loading="lazy" width="415" height="368"><figcaption>Enable Hyper-V</figcaption></figure><h1 id="create-the-virtual-machine">Create the Virtual Machine</h1><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cindr.org/content/images/2022/05/Screenshot-2022-05-20-131246.png" class="kg-image" alt="How Create a Windows 11 Virtual Machine using Hyper-V" loading="lazy" width="946" height="721" srcset="https://cindr.org/content/images/size/w600/2022/05/Screenshot-2022-05-20-131246.png 600w, https://cindr.org/content/images/2022/05/Screenshot-2022-05-20-131246.png 946w" sizes="(min-width: 720px) 720px"><figcaption>Hyper-V Interface</figcaption></figure><h2 id="option-1-use-windows-11-dev-environment">Option 1: Use Windows 11 Dev Environment</h2><p>Click on <strong>Quick Create</strong> and select Windows 11 dev environment then create. It will download the necessary files.</p><p>This is an evaluation copy and it will expire eventually however if you just need somewhere to test things this is the easiest method.<br><br>You can learn more about the evaluation copy <a href="https://developer.microsoft.com/en-us/windows/downloads/virtual-machines/">here</a>.</p><h2 id="option-2-use-windows-11-iso">Option 2: Use Windows 11 ISO</h2><p>You can download the Windows 11 ISO file <a href="https://www.microsoft.com/software-download/windows11">here</a>. Make sure to read the requirements and warnings.</p><p>After downloading the file you want to click <strong>Quick Create </strong>and<strong> </strong>select<strong> Local installation source. </strong></p><h1 id="vm-settings">VM Settings</h1><p>The basic settings you want to change are the <strong>Memory</strong> and <strong>Processor</strong> settings. You should set them based on how much resources you have available on your computer and your indented use for the VM.</p><p>The minimum requirements for Windows 11 are <strong>4 GB</strong> of ram and <strong>2 processor cores</strong>. You can read the rest of the requirements <a href="https://www.microsoft.com/en-us/windows/windows-11-specifications">here</a>.</p><!--kg-card-begin: markdown--><p><strong>System requirements:</strong></p>
<ul>
<li>RAM	4 gigabyte (GB)</li>
<li>Processor	1 GHz&#x202F;or&#x202F;faster with 2 or more cores 64-bit</li>
</ul>
<!--kg-card-end: markdown--><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cindr.org/content/images/2022/05/ram.png" class="kg-image" alt="How Create a Windows 11 Virtual Machine using Hyper-V" loading="lazy" width="722" height="682" srcset="https://cindr.org/content/images/size/w600/2022/05/ram.png 600w, https://cindr.org/content/images/2022/05/ram.png 722w" sizes="(min-width: 720px) 720px"><figcaption>VM Settings</figcaption></figure><p>You can change the other settings now you edit them later. Once you are done click connect and you should be able to start using your new Windows 11 Virtual Machine.</p>]]></content:encoded></item><item><title><![CDATA[How to make a login with Discord button using JavaScript (Express)]]></title><description><![CDATA[<h3 id="video-tutorial">Video Tutorial</h3><figure class="kg-card kg-embed-card"><iframe width="200" height="113" src="https://www.youtube.com/embed/0y-DsaI3ZcM?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></figure><h3 id="getting-started">Getting Started</h3><p>I made a CSS stylesheet using tailwind that is included in the source files. Additionally, I made two pages: index.html, and dashboard.html, which will serve to direct the user to login with discord, and then show them their logged in state.</p><p>Additionally, the &quot;</p>]]></description><link>https://cindr.org/how-to-make-a-login-with-discord-button-using-javascript-express/</link><guid isPermaLink="false">629d491eff77510001b763f4</guid><dc:creator><![CDATA[Martin B]]></dc:creator><pubDate>Mon, 06 Jun 2022 00:25:18 GMT</pubDate><media:content url="https://cindr.org/content/images/2022/06/Login-with-discord-js-ghost.png" medium="image"/><content:encoded><![CDATA[<h3 id="video-tutorial">Video Tutorial</h3><figure class="kg-card kg-embed-card"><iframe width="200" height="113" src="https://www.youtube.com/embed/0y-DsaI3ZcM?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></figure><h3 id="getting-started">Getting Started</h3><img src="https://cindr.org/content/images/2022/06/Login-with-discord-js-ghost.png" alt="How to make a login with Discord button using JavaScript (Express)"><p>I made a CSS stylesheet using tailwind that is included in the source files. Additionally, I made two pages: index.html, and dashboard.html, which will serve to direct the user to login with discord, and then show them their logged in state.</p><p>Additionally, the &quot;server&quot; is handled using express js.</p><h1 id="coding">Coding</h1><h2 id="installing-dependencies">Installing Dependencies</h2><p>Luckily, we only need express js for this project. A real project would be more complex and need a few more things, but we will build off of this.</p><pre><code class="language-console">npm install express</code></pre><h2 id="starter-html">Starter HTML</h2><p>First, we will make an index.html (home page)</p><pre><code class="language-html">&lt;!doctype html&gt;
&lt;html&gt;
&lt;head&gt;
  &lt;meta charset=&quot;UTF-8&quot;&gt;
  &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&gt;
  &lt;base href=&quot;/&quot;&gt;
  &lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;output.css&quot; &gt;
  &lt;link rel=&quot;stylesheet&quot; href=&quot;https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css&quot; integrity=&quot;sha512-KfkfwYDsLkIlwQp6LFnl8zNdLGxu9YAA1QvwINks4PhcElQSvqcyVLLD9aMhXd13uQjoXtEKNosOWaZqXgel0g==&quot; crossorigin=&quot;anonymous&quot; referrerpolicy=&quot;no-referrer&quot; /&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;div class=&quot;flex items-center justify-center h-screen bg-discord-gray text-white&quot; &gt;
        &lt;a id=&quot;login&quot; href=&quot;#discord_token_link&quot; class=&quot;bg-discord-blue  text-xl px-5 py-3 rounded-md font-bold flex items-center space-x-4 hover:bg-gray-600 transition duration-75&quot;&gt;
            &lt;i class=&quot;fa-brands fa-discord text-2xl&quot;&gt;&lt;/i&gt;
            &lt;span&gt;Login with Discord&lt;/span&gt;
        &lt;/a&gt;
    &lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre><p>Next, we will make a dashboard.html (logged in page)</p><pre><code class="language-html">&lt;!doctype html&gt;
&lt;html&gt;
&lt;head&gt;
  &lt;meta charset=&quot;UTF-8&quot;&gt;
  &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&gt;
  &lt;base href=&quot;/&quot;&gt;
  &lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;output.css&quot; &gt;
  &lt;link rel=&quot;stylesheet&quot; href=&quot;https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css&quot; integrity=&quot;sha512-KfkfwYDsLkIlwQp6LFnl8zNdLGxu9YAA1QvwINks4PhcElQSvqcyVLLD9aMhXd13uQjoXtEKNosOWaZqXgel0g==&quot; crossorigin=&quot;anonymous&quot; referrerpolicy=&quot;no-referrer&quot; /&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;div class=&quot;flex items-center justify-center h-screen bg-discord-gray text-white flex-col&quot;&gt;
        &lt;div class=&quot;text-2xl&quot;&gt;Welcome to the dashboard,&lt;/div&gt;
        &lt;div class=&quot;text-4xl mt-3 flex items-center font-medium&quot; &gt;
            &lt;img src=&apos;&apos; id=&quot;avatar&quot; class=&quot;rounded-full w-12 h-12 mr-3&quot;/&gt;
            &lt;div id=&quot;name&quot;&gt;&lt;/div&gt;
        &lt;/div&gt;
        &lt;a href=&quot;/&quot; class=&quot;text-sm mt-5&quot;&gt;Logout&lt;/a&gt;
    &lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre><p>Don&apos;t worry about the style sheet not loading. We will fix this using express routing to allow static files to show up</p><h2 id="express-server-setup">Express Server Setup</h2><p>Create an index.js file and initialize express js.</p><pre><code class="language-js">const path = require(&apos;path&apos;);
const express = require(&apos;express&apos;);


const app = express();</code></pre><p>We will also use a public folder to serve our static output.css file, so create that directory, add your css in there and add this line to your code</p><pre><code class="language-js">app.use(&apos;&apos;,express.static(path.join(__dirname, &apos;public&apos;)));</code></pre><p>Next, we will add two routes, one for our default that will route to index, and the other for the logged in state when we go through the /auth/discord route</p><pre><code class="language-js">app.get(&apos;/&apos;, (request, response) =&gt; {
	return response.sendFile(&apos;index.html&apos;, { root: &apos;.&apos; });
});

app.get(&apos;/auth/discord&apos;, (request, response) =&gt; {
	return response.sendFile(&apos;dashboard.html&apos;, { root: &apos;.&apos; });
});</code></pre><p>We will be serving those files respectively,</p><p>Finally, specify which port your server will run on, and start your server. </p><pre><code class="language-js">const port = &apos;53134&apos;;
app.listen(port, () =&gt; console.log(`App listening at http://localhost:${port}`));</code></pre><p>We should be able to navigate through to our index page if we visit the url: <a href="http://localhost:53134/">http://localhost:53134/</a></p><h3 id="creating-a-redirect">Creating a redirect:</h3><p>Head on over to the <a href="https://discord.com/developers/docs/intro">discord developer portal</a> and go to applications:</p><figure class="kg-card kg-image-card"><img src="https://cindr.org/content/images/2022/06/image.png" class="kg-image" alt="How to make a login with Discord button using JavaScript (Express)" loading="lazy" width="839" height="337" srcset="https://cindr.org/content/images/size/w600/2022/06/image.png 600w, https://cindr.org/content/images/2022/06/image.png 839w" sizes="(min-width: 720px) 720px"></figure><p>From there, create a new application</p><figure class="kg-card kg-image-card"><img src="https://cindr.org/content/images/2022/06/image-1.png" class="kg-image" alt="How to make a login with Discord button using JavaScript (Express)" loading="lazy" width="1244" height="369" srcset="https://cindr.org/content/images/size/w600/2022/06/image-1.png 600w, https://cindr.org/content/images/size/w1000/2022/06/image-1.png 1000w, https://cindr.org/content/images/2022/06/image-1.png 1244w" sizes="(min-width: 720px) 720px"></figure><p>Specify a name</p><figure class="kg-card kg-image-card"><img src="https://cindr.org/content/images/2022/06/image-2.png" class="kg-image" alt="How to make a login with Discord button using JavaScript (Express)" loading="lazy" width="483" height="507"></figure><p>Once created, click on OAuth2 on the side and select &quot;General&quot;</p><h3 id="adding-a-redirect">Adding a redirect</h3><p>Add the following redirect which corresponds to your local host server, and the path that we want express to route from:</p><pre><code>http://localhost:53134/auth/discord</code></pre><figure class="kg-card kg-image-card"><img src="https://cindr.org/content/images/2022/06/image-3.png" class="kg-image" alt="How to make a login with Discord button using JavaScript (Express)" loading="lazy" width="1177" height="204" srcset="https://cindr.org/content/images/size/w600/2022/06/image-3.png 600w, https://cindr.org/content/images/size/w1000/2022/06/image-3.png 1000w, https://cindr.org/content/images/2022/06/image-3.png 1177w" sizes="(min-width: 720px) 720px"></figure><h3 id="getting-a-redirect-url">Getting a redirect url</h3><p>Next, we can use discord to generate us a redirect url, by selecting identity and generating a dynamic url from one of our redirects</p><figure class="kg-card kg-image-card"><img src="https://cindr.org/content/images/2022/06/image-4.png" class="kg-image" alt="How to make a login with Discord button using JavaScript (Express)" loading="lazy" width="1497" height="788" srcset="https://cindr.org/content/images/size/w600/2022/06/image-4.png 600w, https://cindr.org/content/images/size/w1000/2022/06/image-4.png 1000w, https://cindr.org/content/images/2022/06/image-4.png 1497w" sizes="(min-width: 720px) 720px"></figure><p>Copy that url, and paste it into your index.html anchor tag</p><p><strong>Make sure to change &amp;response_type=code to &amp;response_type=token</strong></p><h2 id="handling-our-response-and-auth-code">Handling our response and auth code:</h2><p></p><p>We will deconstruct the get parameters sent to us onload, and redirect the user back to the index screen if they didn&apos;t pass them</p><pre><code class="language-js">window.onload = () =&gt; {
const fragment = new URLSearchParams(window.location.hash.slice(1));
const [accessToken, tokenType] = [fragment.get(&apos;access_token&apos;), fragment.get(&apos;token_type&apos;)];

if (!accessToken) {
    window.location.href(&apos;/&apos;)
    return (document.getElementById(&apos;login&apos;).style.display = &apos;block&apos;);
}


};</code></pre><p>Next, we will handle fetching the data about the user by passing an auth bearer header to discord, and receiving data back about the user</p><pre><code class="language-js">fetch(&apos;https://discord.com/api/users/@me&apos;, {
    headers: {
        authorization: `${tokenType} ${accessToken}`,
    },
})
.then(result =&gt; result.json())
.then(response =&gt; {
    //handle response
})
.catch(console.error);</code></pre><p>Finally, we will change our DOM html to reflect the new data we just received, and we are done!</p><pre><code class="language-js">const { username, discriminator, avatar, id} = response;
//set the welcome username string
document.getElementById(&apos;name&apos;).innerText = ` ${username}#${discriminator}`;

//set the avatar image by constructing a url to access discord&apos;s cdn
document.getElementById(&quot;avatar&quot;).src = `https://cdn.discordapp.com/avatars/${id}/${avatar}.jpg`;</code></pre>]]></content:encoded></item><item><title><![CDATA[How to make a login with Steam button with PHP (OpenID)]]></title><description><![CDATA[<h1 id="video-tutorial">Video Tutorial</h1><figure class="kg-card kg-embed-card"><iframe width="200" height="113" src="https://www.youtube.com/embed/7IzEqAK_PLg?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></figure><h1 id="source-code">Source Code</h1><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://github.com/mbouldo/login-with-steam-php/tree/main"><div class="kg-bookmark-content"><div class="kg-bookmark-title">GitHub - mbouldo/login-with-steam-php: A simple login with Steam starter project using open ID and PHP</div><div class="kg-bookmark-description">A simple login with Steam starter project using open ID and PHP - GitHub - mbouldo/login-with-steam-php: A simple login with Steam starter project using open ID and PHP</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://github.com/fluidicon.png" alt><span class="kg-bookmark-author">GitHub</span></div></div></a></figure>]]></description><link>https://cindr.org/how-to-make-a-login-with-steam-button-with-php-oauth-open/</link><guid isPermaLink="false">62864c55bb6603000139a6ec</guid><category><![CDATA[Coding]]></category><category><![CDATA[PHP Tutorials]]></category><dc:creator><![CDATA[Martin B]]></dc:creator><pubDate>Thu, 19 May 2022 13:59:52 GMT</pubDate><media:content url="https://cindr.org/content/images/2022/05/login-with-steam-ghost.png" medium="image"/><content:encoded><![CDATA[<h1 id="video-tutorial">Video Tutorial</h1><figure class="kg-card kg-embed-card"><iframe width="200" height="113" src="https://www.youtube.com/embed/7IzEqAK_PLg?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></figure><h1 id="source-code">Source Code</h1><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://github.com/mbouldo/login-with-steam-php/tree/main"><div class="kg-bookmark-content"><div class="kg-bookmark-title">GitHub - mbouldo/login-with-steam-php: A simple login with Steam starter project using open ID and PHP</div><div class="kg-bookmark-description">A simple login with Steam starter project using open ID and PHP - GitHub - mbouldo/login-with-steam-php: A simple login with Steam starter project using open ID and PHP</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://github.com/fluidicon.png" alt="How to make a login with Steam button with PHP (OpenID)"><span class="kg-bookmark-author">GitHub</span><span class="kg-bookmark-publisher">mbouldo</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://opengraph.githubassets.com/871ebf71f639f95403143c0c1b9fb973f2a880d05b879c854057d4b2b26496b5/mbouldo/login-with-steam-php" alt="How to make a login with Steam button with PHP (OpenID)"></div></a></figure><h1 id="getting-started">Getting Started</h1><h2 id="starter-html-file-structure">Starter HTML &amp; File Structure</h2><img src="https://cindr.org/content/images/2022/05/login-with-steam-ghost.png" alt="How to make a login with Steam button with PHP (OpenID)"><p>Similar to my &quot;<a href="https://cindr.org/how-to-create-a-login-with-discord-button-in-php/">Login with Discord PHP</a>&quot; guide, we will have a basic landing page with a button to navigate to the auth page (steam), and then be redirected back to a login protected dashboard page.</p><p>Therefore, <strong>index.php</strong> handles the homepage. <strong>dashboard.php </strong>is the login protected dashboard. <strong>init-openId.php</strong> will build parameters and redirect the user to steam.com, and finally, <strong>process-openId.php</strong> will listen for steam&apos;s return data on the authentication.</p><p>The rest of the files uses such as <strong>error.php, </strong>and <strong>logout.php</strong> are not essential, but help with error handling and destroying the user&apos;s session after they have successfully logged in.</p><p>Finally, a tailwind generated <strong>output.css</strong> is used for basic styling and can be found in the source code repository.</p><h3 id="starter-indexphp">Starter index.php</h3><pre><code class="language-html">&lt;!doctype html&gt;
&lt;html&gt;
&lt;head&gt;
  &lt;meta charset=&quot;UTF-8&quot;&gt;
  &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&gt;
  &lt;link href=&quot;./styles/output.css&quot; rel=&quot;stylesheet&quot;&gt;
  &lt;link rel=&quot;stylesheet&quot; href=&quot;https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css&quot; integrity=&quot;sha512-KfkfwYDsLkIlwQp6LFnl8zNdLGxu9YAA1QvwINks4PhcElQSvqcyVLLD9aMhXd13uQjoXtEKNosOWaZqXgel0g==&quot; crossorigin=&quot;anonymous&quot; referrerpolicy=&quot;no-referrer&quot; /&gt;
&lt;/head&gt;
&lt;body class=&quot;bg-blue-400&quot;&gt;
    &lt;div class=&quot;flex items-center justify-center h-screen bg-slate-900 text-white&quot;&gt;
        &lt;a href=&quot;init-openId.php&quot; class=&quot;bg-steam-lightGray  text-xl px-5 py-3 rounded-md font-bold flex items-center space-x-4 hover:bg-gray-600 transition duration-75&quot;&gt;
            &lt;i class=&quot;fa-brands fa-steam text-2xl&quot;&gt;&lt;/i&gt;
            &lt;span&gt;Login with Steam&lt;/span&gt;
        &lt;/a&gt;
    &lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre><h3 id="starter-dashboardphp">Starter dashboard.php</h3><pre><code class="language-html">&lt;!doctype html&gt;
&lt;html&gt;
&lt;head&gt;
  &lt;meta charset=&quot;UTF-8&quot;&gt;
  &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&gt;
  &lt;link href=&quot;./styles/output.css&quot; rel=&quot;stylesheet&quot;&gt;
  &lt;link rel=&quot;stylesheet&quot; href=&quot;https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css&quot; integrity=&quot;sha512-KfkfwYDsLkIlwQp6LFnl8zNdLGxu9YAA1QvwINks4PhcElQSvqcyVLLD9aMhXd13uQjoXtEKNosOWaZqXgel0g==&quot; crossorigin=&quot;anonymous&quot; referrerpolicy=&quot;no-referrer&quot; /&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;div class=&quot;flex items-center justify-center h-screen bg-steam-lightGray text-white flex-col&quot;&gt;
        &lt;div class=&quot;text-2xl&quot;&gt;Welcome to the dashboard,&lt;/div&gt;
        &lt;div class=&quot;text-4xl mt-3 flex items-center font-medium&quot;&gt;&lt;img src=&apos;{{avatar_src}}&apos; class=&quot;rounded-full w-12 h-12 mr-3&quot;/&gt;{{username}}&lt;/div&gt;
        &lt;a href=&quot;logout.php&quot; class=&quot;text-sm mt-5&quot;&gt;Logout&lt;/a&gt;
    &lt;/div&gt;

&lt;/body&gt;
&lt;/html&gt;</code></pre><h3 id="making-dashboardphp-login-protected">Making dashboard.php login protected</h3><p>In order to not allow a random user to directly access this URL, we will start a session at the top of the page and see if the session variable: <strong>logged_in </strong>is equal to true. Currently, it will be <strong>undefined</strong>. But we will see it later in the application.</p><p>Add this to the top of the dashboard.php page:</p><pre><code class="language-php">session_start();
if(!$_SESSION[&apos;logged_in&apos;]){
    header(&quot;location: error.php&quot;);
    exit();
}</code></pre><p><strong>error.php </strong>will be text you want to show the user to notify them they are not logged in.</p><h2 id="redirecting-the-user-for-the-first-time">Redirecting the user for the first time</h2><p>In my opinion, it&apos;s a good idea to have a separate redirect page to initiate external authorization. This wasn&apos;t really obvious with discord which just used a hardcoded URL; here, we will need to build more complex parameters.</p><h3 id="building-open-id-parameters">Building open Id parameters:</h3><p>We need to construct the following paramters which will be passed as a GET query to the intial URL. It will tell steam what protocol we will use, and how to redirect our user back to our server.</p><pre><code class="language-php">$login_url_params = [
    &apos;openid.ns&apos;         =&gt; &apos;http://specs.openid.net/auth/2.0&apos;,
    &apos;openid.mode&apos;       =&gt; &apos;checkid_setup&apos;,
    &apos;openid.return_to&apos;  =&gt; &apos;http://localhost/login-with-steam-yt/process-openId.php&apos;,
    &apos;openid.realm&apos;      =&gt; (!empty($_SERVER[&apos;HTTPS&apos;]) ? &apos;https&apos; : &apos;http&apos;).&apos;://&apos;.$_SERVER[&apos;HTTP_HOST&apos;],
    &apos;openid.identity&apos;   =&gt; &apos;http://specs.openid.net/auth/2.0/identifier_select&apos;,
    &apos;openid.claimed_id&apos; =&gt; &apos;http://specs.openid.net/auth/2.0/identifier_select&apos;,
];</code></pre><h3 id="constructing-our-url-from-the-parameters-and-redirecting">Constructing our URL from the parameters, and redirecting</h3><pre><code class="language-php">$steam_login_url = &apos;https://steamcommunity.com/openid/login&apos;.&apos;?&apos;.http_build_query($login_url_params, &apos;&apos;, &apos;&amp;&apos;);

header(&quot;location: $steam_login_url&quot;);
exit();</code></pre><p>If you did set up your URL correctly, the steam page should look like this: </p><figure class="kg-card kg-image-card"><img src="https://cindr.org/content/images/2022/05/image-2.png" class="kg-image" alt="How to make a login with Steam button with PHP (OpenID)" loading="lazy" width="998" height="591" srcset="https://cindr.org/content/images/size/w600/2022/05/image-2.png 600w, https://cindr.org/content/images/2022/05/image-2.png 998w" sizes="(min-width: 720px) 720px"></figure><p>And once logged in, will look like this:</p><figure class="kg-card kg-image-card"><img src="https://cindr.org/content/images/2022/05/image-1.png" class="kg-image" alt="How to make a login with Steam button with PHP (OpenID)" loading="lazy" width="1022" height="579" srcset="https://cindr.org/content/images/size/w600/2022/05/image-1.png 600w, https://cindr.org/content/images/size/w1000/2022/05/image-1.png 1000w, https://cindr.org/content/images/2022/05/image-1.png 1022w" sizes="(min-width: 720px) 720px"></figure><h2 id="what-happens-after-the-user-logs-in">What happens after the user &quot;logs in&quot;</h2><p>Steam will validate the authentication internally, and then communicate to the OpenID API to compose a request to send back to you, and your server. (We specified the &quot;our server endpoint&quot; in those initial parameters).</p><p>So, we need a file to receive that incoming request, and process the new data we have.</p><p>We are expecting information some kind of token to reference who in fact was validated. Steam will not directly say &quot;Jimmy&quot; was validated, because you could spoof this information.</p><p>The token we receive is in the form of a long set of $_GET parameters, looking a little like this:</p><pre><code class="language-php">Array
(
    [openid_ns] =&gt; http://specs.openid.net/auth/2.0
    [openid_mode] =&gt; id_res
    [openid_op_endpoint] =&gt; https://steamcommunity.com/openid/login
    [openid_claimed_id] =&gt; https://steamcommunity.com/openid/id/76561198068485408
    [openid_identity] =&gt; https://steamcommunity.com/openid/id/76561198068485408
    [openid_return_to] =&gt; http://localhost/login-with-steam-yt/process-openId.php
    [openid_response_nonce] =&gt; 2022-05-20T02:22:02ZL9LZ+XnIhRJAYbiXMNGhaWfAF8c=
    [openid_assoc_handle] =&gt; 1234567890
    [openid_signed] =&gt; signed,op_endpoint,claimed_id,identity,return_to,response_nonce,assoc_handle
    [openid_sig] =&gt; Td6XOTHOCYU22oABLocdFvgsGBk=
)</code></pre><p>We will take this data, and pass it to steam&apos;s open id handler, to see if the request is valid, and see who was validated (steam id).</p><h3 id="constructing-parameters-to-send-to-steam-open-id">Constructing parameters to send to steam open id</h3><p>Initially, we can hardcode some parameters, and then we can </p><pre><code class="language-php">    $params = [
        &apos;openid.assoc_handle&apos; =&gt; $_GET[&apos;openid_assoc_handle&apos;],
        &apos;openid.signed&apos;       =&gt; $_GET[&apos;openid_signed&apos;],
        &apos;openid.sig&apos;          =&gt; $_GET[&apos;openid_sig&apos;],
        &apos;openid.ns&apos;           =&gt; &apos;http://specs.openid.net/auth/2.0&apos;,
        &apos;openid.mode&apos;         =&gt; &apos;check_authentication&apos;,
    ];</code></pre><p>dynamically use the <strong>$_GET[&apos;openid_signed&apos;] </strong>parameter to construct more parameters like so</p><pre><code class="language-php">    $signed = explode(&apos;,&apos;, $_GET[&apos;openid_signed&apos;]);
    
    foreach ($signed as $item) {
        $val = $_GET[&apos;openid_&apos;.str_replace(&apos;.&apos;, &apos;_&apos;, $item)];
        $params[&apos;openid.&apos;.$item] = stripslashes($val);
    }</code></pre><p>Your parameters should look like this:</p><pre><code class="language-php">Array
(
    [openid.assoc_handle] =&gt; 1234567890
    [openid.signed] =&gt; signed,op_endpoint,claimed_id,identity,return_to,response_nonce,assoc_handle
    [openid.sig] =&gt; Td6XOTHOCYU22oABLocdFvgsGBk=
    [openid.ns] =&gt; http://specs.openid.net/auth/2.0
    [openid.mode] =&gt; check_authentication
    [openid.op_endpoint] =&gt; https://steamcommunity.com/openid/login
    [openid.claimed_id] =&gt; https://steamcommunity.com/openid/id/76561198068485408
    [openid.identity] =&gt; https://steamcommunity.com/openid/id/76561198068485408
    [openid.return_to] =&gt; http://localhost/login-with-steam-yt/process-openId.php
    [openid.response_nonce] =&gt; 2022-05-20T02:22:02ZL9LZ+XnIhRJAYbiXMNGhaWfAF8c=
)
</code></pre><h3 id="constructing-headers-for-steams-open-id-endpoint">Constructing headers for steam&apos;s open ID endpoint</h3><p>Similar to cURL, we will construct headers to hit steam&apos;s endpoint with our open id information.</p><pre><code class="language-php">$data = http_build_query($params);
//data prep
$context = stream_context_create([
    &apos;http&apos; =&gt; [
        &apos;method&apos; =&gt; &apos;POST&apos;,
        &apos;header&apos; =&gt; &quot;Accept-language: en\r\n&quot;.
        &quot;Content-type: application/x-www-form-urlencoded\r\n&quot;.
        &apos;Content-Length: &apos;.strlen($data).&quot;\r\n&quot;,
        &apos;content&apos; =&gt; $data,
    ],
]);

//get the data
$result = file_get_contents(&apos;https://steamcommunity.com/openid/login&apos;, false, $context);</code></pre><h3 id="checking-if-result-is-valid">Checking if $result is valid</h3><p>Use regular expression to check if the string contains the correct &quot;valid&quot; syntax, if its valid set the <strong>$steamId</strong></p><pre><code class="language-php">if(preg_match(&quot;#is_valid\s*:\s*true#i&quot;, $result)){
    preg_match(&apos;#^https://steamcommunity.com/openid/id/([0-9]{17,25})#&apos;, $_GET[&apos;openid_claimed_id&apos;], $matches);
    $steamID64 = is_numeric($matches[1]) ? $matches[1] : 0;
    echo &apos;request has been validated by open id, returning the client id (steam id) of: &apos; . $steamID64;    

}else{
    echo &apos;error: unable to validate your request&apos;;
    exit();
}</code></pre><h3 id="using-the-steam-id-to-get-the-user-data">Using the steam id to get the user data</h3><p>You will need a steam API key for this step. To obtain your key, visit <a href="http://steamcommunity.com/dev/apikey">this link.</a></p><p>We use a simple file_get_contents() to get the data on the user, with our API key in the URL.</p><pre><code class="language-php">$response = file_get_contents(&apos;https://api.steampowered.com/ISteamUser/GetPlayerSummaries/v0002/?key=&apos;.$steam_api_key.&apos;&amp;steamids=&apos;.$steamID64);
$response = json_decode($response,true);</code></pre><h3 id="example-return-from-steam-api">Example return from steam API</h3><pre><code class="language-php">Array
(
    [response] =&gt; Array
        (
            [players] =&gt; Array
                (
                    [0] =&gt; Array
                        (
                            [steamid] =&gt; 76561198068485408
                            [communityvisibilitystate] =&gt; 3
                            [profilestate] =&gt; 1
                            [personaname] =&gt; Exit
                            [commentpermission] =&gt; 1
                            [profileurl] =&gt; https://steamcommunity.com/profiles/76561198068485408/
                            [avatar] =&gt; https://steamcdn-a.akamaihd.net/steamcommunity/public/images/avatars/3c/3...
                            [avatarmedium] =&gt; https://steamcdn-a.akamaihd.net/steamcommunity/public/images/avatars/3c/3c...
                            [avatarfull] =&gt; https://steamcdn-a.akamaihd.net/steamcommunity/public/images/avatars/3c/3c2...
                            [avatarhash] =&gt; 3c2ae1c9d9e96429c2a274728b55e71c7e745a40
                            [lastlogoff] =&gt; 1652935474
                            [personastate] =&gt; 0
                            [realname] =&gt; Martin B
                            [primaryclanid] =&gt; 103582791441483516
                            [timecreated] =&gt; 1343770109
                            [personastateflags] =&gt; 0
                            [loccountrycode] =&gt; US
                            [locstatecode] =&gt; 13
                            [loccityid] =&gt; 40043
                        )

                )

        )
</code></pre><p>Since it&apos;s an array of users, we will get the relavent data from the response, and set our session variables.</p><pre><code class="language-php">$userData = $response[&apos;response&apos;][&apos;players&apos;][0];
$_SESSION[&apos;logged_in&apos;] = true;
$_SESSION[&apos;userData&apos;] = [
    &apos;steam_id&apos;=&gt;$userData[&apos;steamid&apos;],
    &apos;name&apos;=&gt;$userData[&apos;personaname&apos;],
    &apos;avatar&apos;=&gt;$userData[&apos;avatarmedium&apos;],
];</code></pre><p>From there, we can redirect the user using a header.</p><pre><code class="language-php">$redirect_url = &quot;dashboard.php&quot;;
header(&quot;Location: $redirect_url&quot;); 
exit();</code></pre><p>Finally, on the dashboard, we append getting the user data from our new session.</p><pre><code class="language-php">&lt;?php
session_start();
if(!$_SESSION[&apos;logged_in&apos;]){
    header(&quot;location: error.php&quot;);
    exit();
}

$username = $_SESSION[&apos;userData&apos;][&apos;name&apos;];
$avatar = $_SESSION[&apos;userData&apos;][&apos;avatar&apos;];

?&gt;
&lt;!doctype html&gt;
&lt;html&gt;
&lt;head&gt;
  &lt;meta charset=&quot;UTF-8&quot;&gt;
  &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&gt;
  &lt;link href=&quot;./styles/output.css&quot; rel=&quot;stylesheet&quot;&gt;
  &lt;link rel=&quot;stylesheet&quot; href=&quot;https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css&quot; integrity=&quot;sha512-KfkfwYDsLkIlwQp6LFnl8zNdLGxu9YAA1QvwINks4PhcElQSvqcyVLLD9aMhXd13uQjoXtEKNosOWaZqXgel0g==&quot; crossorigin=&quot;anonymous&quot; referrerpolicy=&quot;no-referrer&quot; /&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;div class=&quot;flex items-center justify-center h-screen bg-steam-lightGray text-white flex-col&quot;&gt;
        &lt;div class=&quot;text-2xl&quot;&gt;Welcome to the dashboard,&lt;/div&gt;
        &lt;div class=&quot;text-4xl mt-3 flex items-center font-medium&quot;&gt;&lt;img src=&apos;&lt;?php echo $avatar;?&gt;&apos; class=&quot;rounded-full w-12 h-12 mr-3&quot;/&gt;&lt;?php echo $username;?&gt;&lt;/div&gt;
        &lt;a href=&quot;logout.php&quot; class=&quot;text-sm mt-5&quot;&gt;Logout&lt;/a&gt;
    &lt;/div&gt;

&lt;/body&gt;
&lt;/html&gt;</code></pre>]]></content:encoded></item><item><title><![CDATA[Human readable arrays in PHP]]></title><description><![CDATA[<p>When I began using external APIs, I ran into a big problem. I couldn&apos;t read my arrays. They were a bumbling mess that looked like:<br></p><!--kg-card-begin: markdown--><pre><code class="language-php">array(4) { [&quot;time&quot;]=&gt; array(3) { [&quot;updated&quot;]=&gt; string(25) &quot;May 14, 2022 15:45:00 UTC&quot;</code></pre>]]></description><link>https://cindr.org/human-readable-arrays-in-php/</link><guid isPermaLink="false">627fce79cc55a90001359282</guid><category><![CDATA[Coding]]></category><category><![CDATA[PHP Tutorials]]></category><dc:creator><![CDATA[Martin B]]></dc:creator><pubDate>Sat, 14 May 2022 16:00:46 GMT</pubDate><media:content url="https://cindr.org/content/images/2022/05/human_readable_ghost.png" medium="image"/><content:encoded><![CDATA[<img src="https://cindr.org/content/images/2022/05/human_readable_ghost.png" alt="Human readable arrays in PHP"><p>When I began using external APIs, I ran into a big problem. I couldn&apos;t read my arrays. They were a bumbling mess that looked like:<br></p><!--kg-card-begin: markdown--><pre><code class="language-php">array(4) { [&quot;time&quot;]=&gt; array(3) { [&quot;updated&quot;]=&gt; string(25) &quot;May 14, 2022 15:45:00 UTC&quot; [&quot;updatedISO&quot;]=&gt; string(25) &quot;2022-05-14T15:45:00+00:00&quot; [&quot;updateduk&quot;]=&gt; string(25) &quot;May 14, 2022 at 16:45 BST&quot; } [&quot;disclaimer&quot;]=&gt; string(155) &quot;This data was produced from the CoinDesk Bitcoin Price Index (USD). Non-USD currency data converted using hourly conversion rate from openexchangerates.org&quot; [&quot;chartName&quot;]=&gt; string(7) &quot;Bitcoin&quot; [&quot;bpi&quot;]=&gt; array(3) { [&quot;USD&quot;]=&gt; array(5) { [&quot;code&quot;]=&gt; string(3) &quot;USD&quot; [&quot;symbol&quot;]=&gt; string(5) &quot;$&quot; [&quot;rate&quot;]=&gt; string(11) &quot;28,763.1371&quot; [&quot;description&quot;]=&gt; string(20) &quot;United States Dollar&quot; [&quot;rate_float&quot;]=&gt; float(28763.1371) } [&quot;GBP&quot;]=&gt; array(5) { [&quot;code&quot;]=&gt; string(3) &quot;GBP&quot; [&quot;symbol&quot;]=&gt; string(7) &quot;&#xA3;&quot; [&quot;rate&quot;]=&gt; string(11) &quot;23,451.3911&quot; [&quot;description&quot;]=&gt; string(22) &quot;British Pound Sterling&quot; [&quot;rate_float&quot;]=&gt; float(23451.3911) } [&quot;EUR&quot;]=&gt; array(5) { [&quot;code&quot;]=&gt; string(3) &quot;EUR&quot; [&quot;symbol&quot;]=&gt; string(6) &quot;&#x20AC;&quot; [&quot;rate&quot;]=&gt; string(11) &quot;27,625.2674&quot; [&quot;description&quot;]=&gt; string(4) &quot;Euro&quot; [&quot;rate_float&quot;]=&gt; float(27625.2674) } } } Array ( [time] =&gt; Array ( [updated] =&gt; May 14, 2022 15:45:00 UTC [updatedISO] =&gt; 2022-05-14T15:45:00+00:00 [updateduk] =&gt; May 14, 2022 at 16:45 BST ) [disclaimer] =&gt; This data was produced from the CoinDesk Bitcoin Price Index (USD). Non-USD currency data converted using hourly conversion rate from openexchangerates.org [chartName] =&gt; Bitcoin [bpi] =&gt; Array ( [USD] =&gt; Array ( [code] =&gt; USD [symbol] =&gt; $ [rate] =&gt; 28,763.1371 [description] =&gt; United States Dollar [rate_float] =&gt; 28763.1371 ) [GBP] =&gt; Array ( [code] =&gt; GBP [symbol] =&gt; &#xA3; [rate] =&gt; 23,451.3911 [description] =&gt; British Pound Sterling [rate_float] =&gt; 23451.3911 ) [EUR] =&gt; Array ( [code] =&gt; EUR [symbol] =&gt; &#x20AC; [rate] =&gt; 27,625.2674 [description] =&gt; Euro [rate_float] =&gt; 27625.2674 ) ) )
</code></pre>
<!--kg-card-end: markdown--><p>We need it to look more like this:</p><pre><code class="language-php">Array
(
    [time] =&gt; Array
        (
            [updated] =&gt; May 14, 2022 15:54:00 UTC
            [updatedISO] =&gt; 2022-05-14T15:54:00+00:00
            [updateduk] =&gt; May 14, 2022 at 16:54 BST
        )

    [disclaimer] =&gt; This data was produced from the CoinDesk Bitcoin Price Index...
    [chartName] =&gt; Bitcoin
    [bpi] =&gt; Array
        (
            [USD] =&gt; Array
                (
                    [code] =&gt; USD
                    [symbol] =&gt; $
                    [rate] =&gt; 28,769.6520
                    [description] =&gt; United States Dollar
                    [rate_float] =&gt; 28769.652
                )
            ...
        )

)</code></pre><h1 id="youtube-guide">YouTube Guide</h1><figure class="kg-card kg-embed-card"><iframe width="200" height="113" src="https://www.youtube.com/embed/NdjdQDBldg0?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></figure><h1 id="the-magic-code">The magic code</h1><h2 id="how-to-print-an-array">How to print an array</h2><p>There are multiple ways to print an array. &quot;print_r&quot; is the official way, but var_dump will output the arr with more verbose information</p><p>However, both of these options are not human readable.</p><pre><code>print_r($arr);
var_dump($arr);
echo &apos;&lt;pre&gt;&apos;.print_r($arr,true).&apos;&lt;/pre&gt;&apos;;</code></pre><h2 id="making-it-human-readable">Making it human readable</h2><p>If we want indenations, formatting, etc; we can use the following simple line of code:</p><pre><code class="language-php">echo &apos;&lt;pre&gt;&apos;.print_r($arr,true).&apos;&lt;/pre&gt;&apos;;</code></pre><p>However, in projects, I don&apos;t want to type that mess. I put it inside of a function and call it every time I need an array printed. Since I use it so often, I have a <em>very generic name for my function...</em></p><pre><code class="language-php">echo p($arr);

function p($arr){
    return &apos;&lt;pre&gt;&apos;.print_r($arr,true).&apos;&lt;/pre&gt;&apos;;
}</code></pre>]]></content:encoded></item><item><title><![CDATA[How to get a Minecraft Server's player count, MOTD, and status using Javascript]]></title><description><![CDATA[<p>Getting the status of a Minecraft server is very easy using the free MCApi.us API. All it takes is hitting the endpoint with a basic fetch statement, and then parsing the data that is returned and displaying it on your html page.</p><h2 id="video-tutorial">Video Tutorial</h2><p>Feel free to follow along</p>]]></description><link>https://cindr.org/how-to-get-a-minecraft-servers-player-count-motd-and-status-using-javascript/</link><guid isPermaLink="false">627effd1cc55a90001359253</guid><category><![CDATA[Coding]]></category><category><![CDATA[Javascript]]></category><dc:creator><![CDATA[Martin B]]></dc:creator><pubDate>Sat, 14 May 2022 01:06:15 GMT</pubDate><media:content url="https://cindr.org/content/images/2022/05/serverstatus-1.png" medium="image"/><content:encoded><![CDATA[<img src="https://cindr.org/content/images/2022/05/serverstatus-1.png" alt="How to get a Minecraft Server&apos;s player count, MOTD, and status using Javascript"><p>Getting the status of a Minecraft server is very easy using the free MCApi.us API. All it takes is hitting the endpoint with a basic fetch statement, and then parsing the data that is returned and displaying it on your html page.</p><h2 id="video-tutorial">Video Tutorial</h2><p>Feel free to follow along with the video tutorial. I will be using this as a guide to reference code instead of writing it fully in the video.</p><figure class="kg-card kg-embed-card"><iframe width="200" height="113" src="https://www.youtube.com/embed/yZlAMfPM_sA?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></figure><h2 id="getting-started">Getting Started</h2><p>In the starter code in the video, I use a HTML + CSS page that I made off camera. I wanted to keep the tutorial short in order to show how easy it us to plug this stuff in to your existing application. Please feel free to leave feedback if you are interested in how to create this screen. It was built using tailwind CSS.</p><h3 id="where-to-download-started-files">Where to download started files:</h3><p>The starter files can be found in the following github repository. Just navigate over to it, </p><h2 id="coding-tutorial">Coding Tutorial</h2><h3 id="starter-html">Starter HTML</h3><pre><code class="language-html">&lt;body&gt;
    &lt;div&gt;
        &lt;img src=&quot;https://cdn.pixabay.com/photo/2013/07/12/19/25/minecraft-154749_1280.png&quot;  id=&quot;server-icon&quot;/&gt;
        &lt;div&gt;
            &lt;h1 id=&quot;server-ip&quot;&gt;play.myserver.com&lt;/h1&gt;
            &lt;span id=&quot;motd&quot;&gt;A beautiful minecraft server&lt;/span&gt;
            &lt;div&gt;&lt;span id=&quot;player-count&quot;&gt;290&lt;/span&gt; Players Online&lt;/div&gt;
        &lt;/div&gt;
    &lt;/div&gt;
&lt;/body&gt;</code></pre><h3 id="initializing-the-function">Initializing the function</h3><p>We are going to create a function that will accept the <strong>severIp</strong>, and <strong>serverPort </strong>as parameters. We will pass these to the API that will return back the information about the server. </p><pre><code class="language-js">function initServerData(serverIp,serverPort){ 
    // our function will take 2 parameters
    console.log(serverIp);
    console.log(serverPort);
}

initServerData(&quot;play.dawn-mc.net&quot;,&quot;25565&quot;);</code></pre><h3 id="utilizing-the-javascript-fetch-api">Utilizing the JavaScript fetch() API</h3><p>The fetch() API lets us hit an external endpoint. We are expecting a json response, so we will automatically parse our data.</p><p>We are going to be using the MCApi.us free api. It returns a json object on the status of any server you decide to hit. </p><pre><code class="language-js">function initServerData(serverIp,serverPort){
    fetch(&apos;https://mcapi.us/server/status?ip=&apos;+serverIp+&apos;&amp;port=&apos;+serverPort)
    .then(response =&gt; response.json())
    .then(data =&gt; console.log(data));
}</code></pre><p>The <strong>official documentation</strong>, and <strong>support </strong>can be found on <a href="https://mcapi.us/#usage">https://mcapi.us/#usage</a></p><h3 id="handling-the-data-that-we-received">Handling the data that we received</h3><p>Let&apos;s write a function that will take in the data we receive, and output it throughout our HTML.</p><p>Although the object sends a lot more data, we will be expecting: <strong>an MOTD message, a player count, and a favicon.</strong></p><p>This is a sample return json body:</p><pre><code class="language-json">{
    &quot;status&quot;: &quot;success&quot;,
    &quot;online&quot;: true,
    &quot;motd&quot;: &quot;Dawn MC | Let&apos;s build a new ...&quot;,
    &quot;motd_json&quot;: {
        &quot;extra&quot;: [
            {
                &quot;color&quot;: &quot;gold&quot;,
                &quot;text&quot;: &quot;D&quot;
            },
            {
                &quot;color&quot;: &quot;gold&quot;,
                &quot;text&quot;: &quot;a&quot;
            },
            ...
        ],
        &quot;text&quot;: &quot;&quot;
    },
    &quot;favicon&quot;: &quot;data:image/png;base64,iVBORw0KGgoAAA...&quot;,
    &quot;error&quot;: null,
    &quot;players&quot;: {
        &quot;max&quot;: 100,
        &quot;now&quot;: 9,
        &quot;sample&quot;: [
            {
                &quot;name&quot;: &quot;EchoLynne&quot;,
                &quot;id&quot;: &quot;f1b98f4b-8c66-4d77-a53b-f8784c0607cf&quot;
            },
            ...
        ]
    },
    &quot;server&quot;: {
        &quot;name&quot;: &quot;Paper 1.18.2&quot;,
        &quot;protocol&quot;: 758
    },
    &quot;last_updated&quot;: &quot;1652491121&quot;,
    &quot;duration&quot;: &quot;24093588&quot;
}</code></pre><p>As you can see, our relevant information is stored in <strong>returnData.motd</strong>, <strong>returnData.favicon</strong>, and <strong>returnData.players.now.</strong></p><p>The cool thing is that you can get a lot more information out of this API. Such players.sample[] will return the actual individual players on the server, and the MOTD characters are literally colored in the motd_json.</p><h3 id="setting-the-html">Setting the HTML</h3><pre><code class="language-js">function handleServerStatus(data){
    const motd = document.getElementById(&quot;motd&quot;);
    motd.innerHTML = data.motd;

    const playerCounter = document.getElementById(&quot;player-count&quot;);
    playerCounter.innerHTML = data.players.now;

    const logo = document.getElementById(&quot;server-icon&quot;);
    logo.src = data.favicon;

} </code></pre><p>Now that we have all of our html elements selected (be sure to have the corresponding id=&quot;motd&quot;, etc. in your HTML, we can set their innerHTML to our data.</p><h3 id="error-handling">Error Handling</h3><pre><code class="language-js">    function handleServerStatus(data){
        if(data.status==&apos;error&apos;){
            console.log(data.error);
            return false;
        }
        const motd = document.getElementById(&quot;motd&quot;);
        motd.innerHTML = data.motd;

        const playerCounter = document.getElementById(&quot;player-count&quot;);
        playerCounter.innerHTML = data.players.now;

        const logo = document.getElementById(&quot;server-icon&quot;);
        logo.src = data.favicon;
    } </code></pre><h2 id="complete-script">Complete Script</h2><pre><code class="language-html">&lt;script&gt;
    function initServerData(serverIp,serverPort){
        const serverIpElement = document.getElementById(&apos;server-ip&apos;);
        serverIpElement.innerHTML = serverIp;
        fetch(&apos;https://mcapi.us/server/status?ip=&apos;+serverIp+&apos;&amp;port=&apos;+serverPort)
        .then(response =&gt; response.json())
        .then(data =&gt; handleServerStatus(data));
  
        function handleServerStatus(data){
            if(data.status==&apos;error&apos;){
                console.log(data.error);
                return false;
            }
            const motd = document.getElementById(&quot;motd&quot;);
            motd.innerHTML = data.motd;

            const playerCounter = document.getElementById(&quot;player-count&quot;);
            playerCounter.innerHTML = data.players.now;

            const logo = document.getElementById(&quot;server-icon&quot;);
            logo.src = data.favicon;
        } 
    }

    initServerData(&quot;play.dawn-mc.net&quot;,&quot;25565&quot;);
&lt;/script&gt;</code></pre>]]></content:encoded></item><item><title><![CDATA[How to create a login with Discord button in PHP]]></title><description><![CDATA[<h1 id="video-tutorial">Video Tutorial</h1><p>Currently, this tutorial is in video form only. We are working on a companion guide on the website!</p><figure class="kg-card kg-embed-card"><iframe width="200" height="113" src="https://www.youtube.com/embed/w5ZLlnid8g0?start=17&amp;feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></figure><p>Feel free to comment on the video if you have any questions regarding the tutorial!</p>]]></description><link>https://cindr.org/how-to-create-a-login-with-discord-button-in-php/</link><guid isPermaLink="false">627ebc37cc55a900013591fb</guid><category><![CDATA[Coding]]></category><category><![CDATA[PHP Tutorials]]></category><dc:creator><![CDATA[Martin B]]></dc:creator><pubDate>Thu, 12 May 2022 17:30:01 GMT</pubDate><media:content url="https://cindr.org/content/images/2022/05/login-with-discord-thumbnial.png" medium="image"/><content:encoded><![CDATA[<h1 id="video-tutorial">Video Tutorial</h1><img src="https://cindr.org/content/images/2022/05/login-with-discord-thumbnial.png" alt="How to create a login with Discord button in PHP"><p>Currently, this tutorial is in video form only. We are working on a companion guide on the website!</p><figure class="kg-card kg-embed-card"><iframe width="200" height="113" src="https://www.youtube.com/embed/w5ZLlnid8g0?start=17&amp;feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></figure><p>Feel free to comment on the video if you have any questions regarding the tutorial!</p>]]></content:encoded></item></channel></rss>