<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Xlinesoft Blog</title>
	<atom:link href="https://xlinesoft.com/blog/feed/" rel="self" type="application/rss+xml" />
	<link>https://xlinesoft.com/blog</link>
	<description>Building the best web application builder, one byte at the time</description>
	<lastBuildDate>Tue, 17 Feb 2026 14:16:38 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.4.2</generator>
	<item>
		<title>Version 11.3</title>
		<link>https://xlinesoft.com/blog/2025/12/24/version-11-3/</link>
					<comments>https://xlinesoft.com/blog/2025/12/24/version-11-3/#comments</comments>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Wed, 24 Dec 2025 16:20:46 +0000</pubDate>
				<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[PHP]]></category>
		<guid isPermaLink="false">https://xlinesoft.com/blog/?p=3330</guid>

					<description><![CDATA[Version 11.2 was just released and it is the time to start talking about the next version. We compiled a list of features that will be added in version 11.3 and wanted to share it with you. We expect beta version of v11.3 to be available in the second half of April. 1. Intellisense. Code completion in all areas where code can be edited. 2. AI features. Help with writing the code ( PHP, C#, Javascript, CSS, SQL ). Build the whole project skeleton from...<span class="clearfix clearfix-post"></span><a href="https://xlinesoft.com/blog/2025/12/24/version-11-3/" class="more-link">Continue Reading <span class="screen-reader-text">"Version 11.3"</span> <span class="meta-nav">&#8594;</span></a>]]></description>
										<content:encoded><![CDATA[<p><a href="https://xlinesoft.com/blog/2025/12/10/version-11-2/">Version 11.2</a> was just released and it is the time to start talking about the next version. We compiled a list of features that will be added in version 11.3 and wanted to share it with you. We expect beta version of v11.3 to be available in the second half of April. </p>
<p><a href="https://xlinesoft.com/blog/wp-content/uploads/2025/12/6c8ddb98-71e7-40c4-ba69-3a75657c6e0f.png"><img fetchpriority="high" decoding="async" src="https://xlinesoft.com/blog/wp-content/uploads/2025/12/6c8ddb98-71e7-40c4-ba69-3a75657c6e0f-600x600.png" alt="" width="600" height="600" class="alignnone size-medium wp-image-3331" srcset="https://xlinesoft.com/blog/wp-content/uploads/2025/12/6c8ddb98-71e7-40c4-ba69-3a75657c6e0f-600x600.png 600w, https://xlinesoft.com/blog/wp-content/uploads/2025/12/6c8ddb98-71e7-40c4-ba69-3a75657c6e0f-150x150.png 150w, https://xlinesoft.com/blog/wp-content/uploads/2025/12/6c8ddb98-71e7-40c4-ba69-3a75657c6e0f-768x768.png 768w, https://xlinesoft.com/blog/wp-content/uploads/2025/12/6c8ddb98-71e7-40c4-ba69-3a75657c6e0f-120x120.png 120w, https://xlinesoft.com/blog/wp-content/uploads/2025/12/6c8ddb98-71e7-40c4-ba69-3a75657c6e0f.png 1024w" sizes="(max-width: 600px) 100vw, 600px" /></a><br />
<span id="more-3330"></span></p>
<p>1. Intellisense. Code completion in all areas where code can be edited. </p>
<p>2. AI features. Help with writing the code ( PHP, C#, Javascript, CSS, SQL ). Build the whole project skeleton from a prompt. </p>
<p>3. More built-in backup options. Option to backup on every project save. </p>
<p>4. Save project as template</p>
<p>5. Export/import of individual objects between projects. We are talking about exporting tables, page designs, buttons etc. </p>
<p>6. Small things. Adding search to all dialogs where more than a dozen objects is listed: list of project, list of buttons or code snippets etc. </p>
<p>Year 2026 is going to very exciting!</p>
]]></content:encoded>
					
					<wfw:commentRss>https://xlinesoft.com/blog/2025/12/24/version-11-3/feed/</wfw:commentRss>
			<slash:comments>6</slash:comments>
		
		
			</item>
		<item>
		<title>Version 11.2</title>
		<link>https://xlinesoft.com/blog/2025/12/10/version-11-2/</link>
					<comments>https://xlinesoft.com/blog/2025/12/10/version-11-2/#comments</comments>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Wed, 10 Dec 2025 15:50:13 +0000</pubDate>
				<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[News]]></category>
		<category><![CDATA[PHP]]></category>
		<guid isPermaLink="false">https://xlinesoft.com/blog/?p=3236</guid>

					<description><![CDATA[The final version of PHPRunner/ASPRunner.NET 11.2 is here! To download a registered version logon to your control panel account and find download links under &#8216;My purchases&#8217;. All others can find trial version links below. Trial version download links PHPRunner 11.2 for Windows trial &#160;&#160; ASPRunner.NET 11.2 for Windows trial PHPRunner 11.2 for Mac trial PHPRunner 11.2 for Linux (Debian) trial PHPRunner 11.2 for Linux (RedHat) trial You can install and run it side by side with versions 10.x and 11.1. Existing software functionality will not...<span class="clearfix clearfix-post"></span><a href="https://xlinesoft.com/blog/2025/12/10/version-11-2/" class="more-link">Continue Reading <span class="screen-reader-text">"Version 11.2"</span> <span class="meta-nav">&#8594;</span></a>]]></description>
										<content:encoded><![CDATA[<p>The final version of PHPRunner/ASPRunner.NET 11.2 is here! To download a registered version logon to your <a href='https://xlinesoft.com/dss/support.php'>control panel</a> account and find download links under &#8216;My purchases&#8217;. </p>
<p>All others can find trial version links below. </p>
<h3>Trial version download links</h3>
<p><a href="https://asprunner.com/files/phprunner-trial.exe" class="btn_purple" style="color: white;" contenteditable="false" style="cursor: pointer;">PHPRunner 11.2 for Windows trial</a><br />
&nbsp;&nbsp;<br />
<a href="https://asprunner.com/files/asprunnernet-trial.exe" class="btn_purple" style="color: white;" contenteditable="false" style="cursor: pointer;">ASPRunner.NET 11.2 for Windows trial</a></p>
<p><a href="https://asprunner.com/files/phprunner-trial.dmg" class="btn_purple" style="color: white;" contenteditable="false" style="cursor: pointer;">PHPRunner 11.2 for Mac trial</a></p>
<p><a href="https://asprunner.com/files/phprunner-trial.deb" class="btn_purple" style="color: white;" contenteditable="false" style="cursor: pointer;">PHPRunner 11.2 for Linux (Debian) trial</a></p>
<p><a href="https://asprunner.com/files/phprunner-trial.rpm" class="btn_purple" style="color: white;" contenteditable="false" style="cursor: pointer;">PHPRunner 11.2 for Linux (RedHat) trial</a></p>
<p>You can install and run it side by side with versions 10.x and 11.1. Existing software functionality will not be affected. Just make sure you do not launch previous version and v11.2 at the same time if you use a built-in database to store projects. </p>
<p>This new version comes with ten improvements. </p>
<h3>1. Cards layout on the List page</h3>
<p>Similar to vertical or columns layout but lightweight. No field names, just the data. Fixed width and height. View page of the record can be open by click on the whole card on on one of the fields. Customization: list of fields, layout, fonts, colors, paddings, borders, rounded corners. </p>
<p><a href="https://xlinesoft.com/blog/wp-content/uploads/2025/10/cards_web.png"><img decoding="async" src="https://xlinesoft.com/blog/wp-content/uploads/2025/10/cards_web-600x362.png" alt="" width="600" height="362" class="alignnone size-medium wp-image-3284" srcset="https://xlinesoft.com/blog/wp-content/uploads/2025/10/cards_web-600x362.png 600w, https://xlinesoft.com/blog/wp-content/uploads/2025/10/cards_web-1024x618.png 1024w, https://xlinesoft.com/blog/wp-content/uploads/2025/10/cards_web-768x463.png 768w, https://xlinesoft.com/blog/wp-content/uploads/2025/10/cards_web-1536x927.png 1536w, https://xlinesoft.com/blog/wp-content/uploads/2025/10/cards_web.png 1667w" sizes="(max-width: 600px) 100vw, 600px" /></a><br />
<span id="more-3236"></span></p>
<h3>2. Two new visual themes</h3>
<p>New visual themes are named Futuro (light) and Obsidian (dark). You can choose them on the Style Editor screen. They are modern, sleek and lightweight. </p>
<p><a href="https://xlinesoft.com/blog/wp-content/uploads/2025/12/light.png"><img decoding="async" src="https://xlinesoft.com/blog/wp-content/uploads/2025/12/light-600x325.png" alt="" width="600" height="325" class="alignnone size-medium wp-image-3311" srcset="https://xlinesoft.com/blog/wp-content/uploads/2025/12/light-600x325.png 600w, https://xlinesoft.com/blog/wp-content/uploads/2025/12/light-1024x555.png 1024w, https://xlinesoft.com/blog/wp-content/uploads/2025/12/light-768x416.png 768w, https://xlinesoft.com/blog/wp-content/uploads/2025/12/light-1536x832.png 1536w, https://xlinesoft.com/blog/wp-content/uploads/2025/12/light.png 1920w" sizes="(max-width: 600px) 100vw, 600px" /></a></p>
<p><a href="https://xlinesoft.com/blog/wp-content/uploads/2025/12/dark.png"><img loading="lazy" decoding="async" src="https://xlinesoft.com/blog/wp-content/uploads/2025/12/dark-600x323.png" alt="" width="600" height="323" class="alignnone size-medium wp-image-3309" srcset="https://xlinesoft.com/blog/wp-content/uploads/2025/12/dark-600x323.png 600w, https://xlinesoft.com/blog/wp-content/uploads/2025/12/dark-1024x550.png 1024w, https://xlinesoft.com/blog/wp-content/uploads/2025/12/dark-768x413.png 768w, https://xlinesoft.com/blog/wp-content/uploads/2025/12/dark-1536x826.png 1536w, https://xlinesoft.com/blog/wp-content/uploads/2025/12/dark.png 1920w" sizes="(max-width: 600px) 100vw, 600px" /></a></p>
<h3>3. Three new welcome page layouts</h3>
<p>New Welcome page layouts are called Nebula, Optima and Sonic. You can switch between them while on the Page Designer screen and menu page is open. Here is an example of how Nebula layout looks. </p>
<p><a href="https://xlinesoft.com/blog/wp-content/uploads/2025/12/welcome.png"><img loading="lazy" decoding="async" src="https://xlinesoft.com/blog/wp-content/uploads/2025/12/welcome-600x376.png" alt="" width="600" height="376" class="alignnone size-medium wp-image-3310" srcset="https://xlinesoft.com/blog/wp-content/uploads/2025/12/welcome-600x376.png 600w, https://xlinesoft.com/blog/wp-content/uploads/2025/12/welcome-1024x641.png 1024w, https://xlinesoft.com/blog/wp-content/uploads/2025/12/welcome-768x481.png 768w, https://xlinesoft.com/blog/wp-content/uploads/2025/12/welcome.png 1462w" sizes="(max-width: 600px) 100vw, 600px" /></a></p>
<h3>4. Dashboards tabs</h3>
<p>You can combine several dashboard elements into a single one and use tabs to switch between them. </p>
<p><a href="https://xlinesoft.com/blog/wp-content/uploads/2025/12/dashboard_tabs.png"><img loading="lazy" decoding="async" src="https://xlinesoft.com/blog/wp-content/uploads/2025/12/dashboard_tabs-600x402.png" alt="" width="600" height="402" class="alignnone size-medium wp-image-3308" srcset="https://xlinesoft.com/blog/wp-content/uploads/2025/12/dashboard_tabs-600x402.png 600w, https://xlinesoft.com/blog/wp-content/uploads/2025/12/dashboard_tabs-768x515.png 768w, https://xlinesoft.com/blog/wp-content/uploads/2025/12/dashboard_tabs.png 786w" sizes="(max-width: 600px) 100vw, 600px" /></a></p>
<h3>5. Dashboard widgets</h3>
<p>Similar to dashboard code snippets but easier to customize. </p>
<p><a href="https://xlinesoft.com/blog/wp-content/uploads/2025/12/widgets.png"><img loading="lazy" decoding="async" src="https://xlinesoft.com/blog/wp-content/uploads/2025/12/widgets-600x128.png" alt="" width="600" height="128" class="alignnone size-medium wp-image-3316" srcset="https://xlinesoft.com/blog/wp-content/uploads/2025/12/widgets-600x128.png 600w, https://xlinesoft.com/blog/wp-content/uploads/2025/12/widgets-768x164.png 768w, https://xlinesoft.com/blog/wp-content/uploads/2025/12/widgets.png 853w" sizes="(max-width: 600px) 100vw, 600px" /></a></p>
<h3>6. SMTP with OAuth support</h3>
<p>At this moment we support Gmail Workplace and Microsoft Exchange accounts.</p>
<p><a href="https://xlinesoft.com/blog/wp-content/uploads/2025/12/oauth.png"><img loading="lazy" decoding="async" src="https://xlinesoft.com/blog/wp-content/uploads/2025/12/oauth-600x456.png" alt="" width="600" height="456" class="alignnone size-medium wp-image-3326" srcset="https://xlinesoft.com/blog/wp-content/uploads/2025/12/oauth-600x456.png 600w, https://xlinesoft.com/blog/wp-content/uploads/2025/12/oauth-768x583.png 768w, https://xlinesoft.com/blog/wp-content/uploads/2025/12/oauth.png 828w" sizes="(max-width: 600px) 100vw, 600px" /></a></p>
<h3>7. &#8220;Javascript Create TinyMCE&#8221; event for TinyMCE customization</h3>
<p>This new event allows you to customize TinyMCE editor behavior across the whole project. </p>
<p><a href="https://xlinesoft.com/blog/wp-content/uploads/2025/12/tinymce.png"><img loading="lazy" decoding="async" src="https://xlinesoft.com/blog/wp-content/uploads/2025/12/tinymce-600x309.png" alt="" width="600" height="309" class="alignnone size-medium wp-image-3324" srcset="https://xlinesoft.com/blog/wp-content/uploads/2025/12/tinymce-600x309.png 600w, https://xlinesoft.com/blog/wp-content/uploads/2025/12/tinymce-768x396.png 768w, https://xlinesoft.com/blog/wp-content/uploads/2025/12/tinymce.png 896w" sizes="(max-width: 600px) 100vw, 600px" /></a></p>
<h3>8. ‘View as’ option Copy value to clipboard</h3>
<p>This option can be enabled for any text field under &#8216;View as&#8217; settings.</p>
<p><a href="https://xlinesoft.com/blog/wp-content/uploads/2025/12/clipboard.png"><img loading="lazy" decoding="async" src="https://xlinesoft.com/blog/wp-content/uploads/2025/12/clipboard-600x88.png" alt="" width="600" height="88" class="alignnone size-medium wp-image-3320" srcset="https://xlinesoft.com/blog/wp-content/uploads/2025/12/clipboard-600x88.png 600w, https://xlinesoft.com/blog/wp-content/uploads/2025/12/clipboard.png 603w" sizes="(max-width: 600px) 100vw, 600px" /></a></p>
<h3>9. Foldable elements in dashboards</h3>
<p>All dashboard elements can be folded by clicking on their header. </p>
<p><a href="https://xlinesoft.com/blog/wp-content/uploads/2025/12/foldable.png"><img loading="lazy" decoding="async" src="https://xlinesoft.com/blog/wp-content/uploads/2025/12/foldable-600x376.png" alt="" width="600" height="376" class="alignnone size-medium wp-image-3318" srcset="https://xlinesoft.com/blog/wp-content/uploads/2025/12/foldable-600x376.png 600w, https://xlinesoft.com/blog/wp-content/uploads/2025/12/foldable-1024x641.png 1024w, https://xlinesoft.com/blog/wp-content/uploads/2025/12/foldable-768x481.png 768w, https://xlinesoft.com/blog/wp-content/uploads/2025/12/foldable.png 1462w" sizes="(max-width: 600px) 100vw, 600px" /></a></p>
<h3>10. Show details key column as a hyperlink</h3>
<p>Hyperlink points to the View page of the master and can be open in the same window, in a new window or in a popup. The same functionality for the Lookup Wizard field in view mode. On screenshot below OrderID is a foreign column in &#8216;Order Details&#8217; table. It is set to open master table data in a popup.  </p>
<p><a href="https://xlinesoft.com/blog/wp-content/uploads/2025/12/foreign.png"><img loading="lazy" decoding="async" src="https://xlinesoft.com/blog/wp-content/uploads/2025/12/foreign-600x480.png" alt="" width="600" height="480" class="alignnone size-medium wp-image-3322" srcset="https://xlinesoft.com/blog/wp-content/uploads/2025/12/foreign-600x480.png 600w, https://xlinesoft.com/blog/wp-content/uploads/2025/12/foreign-768x614.png 768w, https://xlinesoft.com/blog/wp-content/uploads/2025/12/foreign.png 1002w" sizes="(max-width: 600px) 100vw, 600px" /></a></p>
<p>Enjoy!</p>
]]></content:encoded>
					
					<wfw:commentRss>https://xlinesoft.com/blog/2025/12/10/version-11-2/feed/</wfw:commentRss>
			<slash:comments>14</slash:comments>
		
		
			</item>
		<item>
		<title>Version 11.2 &#8211; work in progress</title>
		<link>https://xlinesoft.com/blog/2025/10/30/version-11-2-work-in-progress/</link>
					<comments>https://xlinesoft.com/blog/2025/10/30/version-11-2-work-in-progress/#comments</comments>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Thu, 30 Oct 2025 15:41:17 +0000</pubDate>
				<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[News]]></category>
		<category><![CDATA[PHP]]></category>
		<guid isPermaLink="false">https://xlinesoft.com/blog/?p=3276</guid>

					<description><![CDATA[Just wanted to share a preview of a couple of new features coming in version 11.2. This update is mostly about UI improvements in the generated web applications and we&#8217;ll show you new cards layout and dashboard improvements. More details on what is new in version 11.2. 1. Cards layout Cards layout is a compact way to present the information on the List page. Consistent design, all cards look the same, automatically responsive, adjusts to the screen size. No extra information like field names. Previously...<span class="clearfix clearfix-post"></span><a href="https://xlinesoft.com/blog/2025/10/30/version-11-2-work-in-progress/" class="more-link">Continue Reading <span class="screen-reader-text">"Version 11.2 &#8211; work in progress"</span> <span class="meta-nav">&#8594;</span></a>]]></description>
										<content:encoded><![CDATA[<p>Just wanted to share a preview of a couple of new features coming in version 11.2. This update is mostly about UI improvements in the generated web applications and we&#8217;ll show you new cards layout and dashboard improvements.</p>
<p><a target="_new" href="https://xlinesoft.com/blog/2025/09/23/version-11-2/" rel="noopener">More details on what is new in version 11.2. </a></p>
<h3>1. Cards layout</h3>
<p>Cards layout is a compact way to present the information on the List page. Consistent design, all cards look the same, automatically responsive, adjusts to the screen size. No extra information like field names. Previously this required some trickery and now this is a built-in feature. Take a look at this example. </p>
<p><a href="https://xlinesoft.com/blog/wp-content/uploads/2025/10/cards_web.png"><img loading="lazy" decoding="async" src="https://xlinesoft.com/blog/wp-content/uploads/2025/10/cards_web-600x362.png" alt="" width="600" height="362" class="alignnone size-medium wp-image-3284" srcset="https://xlinesoft.com/blog/wp-content/uploads/2025/10/cards_web-600x362.png 600w, https://xlinesoft.com/blog/wp-content/uploads/2025/10/cards_web-1024x618.png 1024w, https://xlinesoft.com/blog/wp-content/uploads/2025/10/cards_web-768x463.png 768w, https://xlinesoft.com/blog/wp-content/uploads/2025/10/cards_web-1536x927.png 1536w, https://xlinesoft.com/blog/wp-content/uploads/2025/10/cards_web.png 1667w" sizes="(max-width: 600px) 100vw, 600px" /></a><br />
<span id="more-3276"></span></p>
<p>Cards layout can be customized in the Page Designer. You can choose which fields will be displayed and what are their types: image, title, subtitle, price etc. </p>
<p><a href="https://xlinesoft.com/blog/wp-content/uploads/2025/10/cards_designer.png"><img loading="lazy" decoding="async" src="https://xlinesoft.com/blog/wp-content/uploads/2025/10/cards_designer-600x348.png" alt="" width="600" height="348" class="alignnone size-medium wp-image-3283" srcset="https://xlinesoft.com/blog/wp-content/uploads/2025/10/cards_designer-600x348.png 600w, https://xlinesoft.com/blog/wp-content/uploads/2025/10/cards_designer-1024x595.png 1024w, https://xlinesoft.com/blog/wp-content/uploads/2025/10/cards_designer-768x446.png 768w, https://xlinesoft.com/blog/wp-content/uploads/2025/10/cards_designer-1536x892.png 1536w, https://xlinesoft.com/blog/wp-content/uploads/2025/10/cards_designer.png 1624w" sizes="(max-width: 600px) 100vw, 600px" /></a></p>
<h3>2. Dashboard improvements</h3>
<p>Two main new features are tabbed elements and foldable elements. You can now fit even more info into a single dashboard using tabbed elements. This is how it looks in the generated application. You can see &#8216;Customers&#8217; tabbed section including multiple elements. You can also see &#8216;Alphabetical list pf products&#8217; element being collapsed. </p>
<p><a href="https://xlinesoft.com/blog/wp-content/uploads/2025/10/image-5.png"><img loading="lazy" decoding="async" src="https://xlinesoft.com/blog/wp-content/uploads/2025/10/image-5-600x420.png" alt="" width="600" height="420" class="alignnone size-medium wp-image-3280" srcset="https://xlinesoft.com/blog/wp-content/uploads/2025/10/image-5-600x420.png 600w, https://xlinesoft.com/blog/wp-content/uploads/2025/10/image-5-1024x716.png 1024w, https://xlinesoft.com/blog/wp-content/uploads/2025/10/image-5-768x537.png 768w, https://xlinesoft.com/blog/wp-content/uploads/2025/10/image-5.png 1352w" sizes="(max-width: 600px) 100vw, 600px" /></a></p>
<p>And here is how it looks in the Page Designer. You can see tabbed section on the left side and properties like &#8216;foldable&#8217; and &#8216;closed initially&#8217; on the right. </p>
<p><a href="https://xlinesoft.com/blog/wp-content/uploads/2025/10/image-6.png"><img loading="lazy" decoding="async" src="https://xlinesoft.com/blog/wp-content/uploads/2025/10/image-6-600x323.png" alt="" width="600" height="323" class="alignnone size-medium wp-image-3279" srcset="https://xlinesoft.com/blog/wp-content/uploads/2025/10/image-6-600x323.png 600w, https://xlinesoft.com/blog/wp-content/uploads/2025/10/image-6-1024x550.png 1024w, https://xlinesoft.com/blog/wp-content/uploads/2025/10/image-6-768x413.png 768w, https://xlinesoft.com/blog/wp-content/uploads/2025/10/image-6-1536x826.png 1536w, https://xlinesoft.com/blog/wp-content/uploads/2025/10/image-6.png 1920w" sizes="(max-width: 600px) 100vw, 600px" /></a></p>
]]></content:encoded>
					
					<wfw:commentRss>https://xlinesoft.com/blog/2025/10/30/version-11-2-work-in-progress/feed/</wfw:commentRss>
			<slash:comments>3</slash:comments>
		
		
			</item>
		<item>
		<title>Using Azure Key Vault to store connection strings</title>
		<link>https://xlinesoft.com/blog/2025/10/15/using-azure-key-vault-to-store-connection-strings/</link>
					<comments>https://xlinesoft.com/blog/2025/10/15/using-azure-key-vault-to-store-connection-strings/#respond</comments>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Wed, 15 Oct 2025 16:13:44 +0000</pubDate>
				<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Tutorials]]></category>
		<guid isPermaLink="false">https://xlinesoft.com/blog/?p=3260</guid>

					<description><![CDATA[Azure Key Vault offers secure storage for sensitive information like passwords, secrets etc. If you host your PHPRunner or ASPRunner.NET application on Azure, it will makes sense to store your connection strings in Key Vault. In this article we&#8217;ll show you how this can be done. Creating Key Vault in Azure 1. Create an application in Azure. Write down tenantId, clientId and clientSecret values. 2. Logon to Azure and create a subscription. You need to specify subscription name and select a billing account. More info:...<span class="clearfix clearfix-post"></span><a href="https://xlinesoft.com/blog/2025/10/15/using-azure-key-vault-to-store-connection-strings/" class="more-link">Continue Reading <span class="screen-reader-text">"Using Azure Key Vault to store connection strings"</span> <span class="meta-nav">&#8594;</span></a>]]></description>
										<content:encoded><![CDATA[<p>Azure Key Vault offers secure storage for sensitive information like passwords, secrets etc. If you host your PHPRunner or ASPRunner.NET application on Azure, it will makes sense to store your connection strings in Key Vault. In this article we&#8217;ll show you how this can be done.</p>
<p><a href="https://xlinesoft.com/blog/wp-content/uploads/2025/10/azure_key_vault2.png"><img loading="lazy" decoding="async" src="https://xlinesoft.com/blog/wp-content/uploads/2025/10/azure_key_vault2-600x315.png" alt="" width="600" height="315" class="alignnone size-medium wp-image-3272" srcset="https://xlinesoft.com/blog/wp-content/uploads/2025/10/azure_key_vault2-600x315.png 600w, https://xlinesoft.com/blog/wp-content/uploads/2025/10/azure_key_vault2-768x403.png 768w, https://xlinesoft.com/blog/wp-content/uploads/2025/10/azure_key_vault2.png 772w" sizes="(max-width: 600px) 100vw, 600px" /></a><br />
<span id="more-3260"></span></p>
<h3>Creating Key Vault in Azure</h3>
<p>1. Create an application in Azure. Write down tenantId, clientId and clientSecret values.</p>
<p>2. Logon to <a href="https://portal.azure.com/#home">Azure</a> and create a subscription. You need to specify subscription name and select a billing account. </p>
<p>More info:<br />
<a href="https://learn.microsoft.com/ru-ru/azure/cost-management-billing/manage/create-subscription">https://learn.microsoft.com/ru-ru/azure/cost-management-billing/manage/create-subscription</a></p>
<p>3. Go back to portal home and proceed to Key Vaults. Click &#8216;Create&#8217;. Select a subscription, select a Resource group ( or create a new one ). Enter Key Vault name. </p>
<p>4. Now it is the time to assign access permissions. Under the Key Vault you just created proceed to &#8216;Access control (IAM)&#8217;. Add -> Add Role assigment, select &#8216;Key Vault Certificates Officer&#8217; using search option, click &#8216;Next&#8217;. Select &#8216;User, group, or service principal&#8217; </p>
<p>Click &#8216;Select members&#8217; search for your application name and select it. . в поисковой строке справа найти свое приложение (не пользолвателя). Next, Review + assign. </p>
<p>Permissions may take a bit of time to be applied but in our situation it worked right away. </p>
<p>5. Create a secret. The secret is the actual object that stores the sensitive information, database password in our case. Select your Key Vault and under Objects -> Secrets -> Generate/Import enter the name of the secret ( &#8220;pass&#8221; in our case ) and its value. </p>
<p>Now we are ready to use this in our code. </p>
<h3>Using Key Vault in PHPRunner</h3>
<p>1. Under Style Editor -> Custom Files add a new file named keyvault.php. Paste the code below and use your own values of tenantId, clientId and clientSecret. </p>
<div class="my-syntax-highlighter">
<pre><textarea id="mshighlighter" class="mshighlighter" language="php" name="mshighlighter" >
<?php
function getSecret($secretName){
	$tenantId = '...';
	$clientId = '...'; 
	$clientSecret = '...';
	$vaultUrl = "https://xkvault.vault.azure.net/";

	$url = "https://login.microsoftonline.com/".$tenantId."/oauth2/token";
	$parameters = array(
		'grant_type' => 'client_credentials',
		'client_id' => $clientId,
		'client_secret' => $clientSecret,
		'resource' => 'https://vault.azure.net'
	);
	$headers = array("Content-Type"=>"application/x-www-form-urlencoded");
	$response = runner_post_request($url, $parameters, $headers);

	$json = runner_json_decode($response["content"]);
	if (!isset($json['access_token'])) {
		throw new Exception("Failed to get access token: " . $response);
	}
	$accessToken = $json['access_token'];

	$url = $vaultUrl . "secrets/".$secretName."?api-version=7.3";

	$headers = array(
		"Authorization"=>"Bearer ".$accessToken,
		"Content-Type"=>"application/json"
	);
	$response = runner_http_request($url, "", "GET", $headers);
	$result = runner_json_decode($response["content"]);
	return $result['value'];
}
?></textarea></pre>
</div>
<p>2. An example of using Key Vault in your application. We will create a new Server Database Connection and will retrieve database password from Key Vault. In this example we use MySQL database.</p>
<div class="my-syntax-highlighter">
<pre><textarea id="mshighlighter" class="mshighlighter" language="php" name="mshighlighter" >
include("keyvault.php");
$host="localhost";
$user="root";
$pwd=getSecret("pass");
$port="";
$sys_dbname="cars";</textarea></pre>
</div>
<h3>Using Key Vault in ASPRunner.NET</h3>
<p>1.  Under Style Editor -> Custom Files add a new file named keyvault.cs. Paste the code below and use your own values of tenantId, clientId and clientSecret. </p>
<div class="my-syntax-highlighter">
<pre><textarea id="mshighlighter" class="mshighlighter" language="" name="mshighlighter" >
using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.Mvc;
using System.Reflection;
using runnerDotNet;
namespace runnerDotNet
{
	public partial class CommonFunctions
	{
		public static XVar getSecret(dynamic secretName)
		{
			dynamic accessToken = null, clientId = null, clientSecret = null, headers = null, json = XVar.Array(), parameters = null, result = XVar.Array(), tenantId = null, url = null, var_response = XVar.Array(), vaultUrl = null;
			tenantId = new XVar("...");
			clientId = new XVar("...");
			clientSecret = new XVar("...");
			vaultUrl = new XVar("https://xkvault.vault.azure.net/");
			url = XVar.Clone(MVCFunctions.Concat("https://login.microsoftonline.com/", tenantId, "/oauth2/token"));
			parameters = XVar.Clone(new XVar("grant_type", "client_credentials", "client_id", clientId, "client_secret", clientSecret, "resource", "https://vault.azure.net"));
			headers = XVar.Clone(new XVar("Content-Type", "application/x-www-form-urlencoded"));
			var_response = XVar.Clone(MVCFunctions.runner_post_request((XVar)(url), (XVar)(parameters), (XVar)(headers)));
			json = XVar.Clone(CommonFunctions.runner_json_decode((XVar)(var_response["content"])));
			if(XVar.Pack(!(XVar)(json.KeyExists("access_token"))))
			{
				new Exception((XVar)(MVCFunctions.Concat("Failed to get access token: ", var_response)));
			}
			accessToken = XVar.Clone(json["access_token"]);
			url = XVar.Clone(MVCFunctions.Concat(vaultUrl, "secrets/", secretName, "?api-version=7.3"));
			headers = XVar.Clone(new XVar("Authorization", MVCFunctions.Concat("Bearer ", accessToken), "Content-Type", "application/json"));
			var_response = XVar.Clone(MVCFunctions.runner_http_request((XVar)(url), new XVar(""), new XVar("GET"), (XVar)(headers)));
			result = XVar.Clone(CommonFunctions.runner_json_decode((XVar)(var_response["content"])));
			return result["value"];
		}
	}
}</textarea></pre>
</div>
<p>2. In BeforeConnect event use the following code:</p>
<div class="my-syntax-highlighter">
<pre><textarea id="mshighlighter" class="mshighlighter" language="" name="mshighlighter" >
dynamic pass = CommonFunctions.getSecret("pass");
GlobalVars.ConnectionStrings["conn"] = MVCFunctions.Concat("Server=localhost;Database=cars;User Id=root;Password=",pass);</textarea></pre>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://xlinesoft.com/blog/2025/10/15/using-azure-key-vault-to-store-connection-strings/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Moving logic from Javascript to the database</title>
		<link>https://xlinesoft.com/blog/2025/09/04/moving-logic-from-javascript-to-the-database/</link>
					<comments>https://xlinesoft.com/blog/2025/09/04/moving-logic-from-javascript-to-the-database/#comments</comments>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Thu, 04 Sep 2025 22:07:33 +0000</pubDate>
				<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Tutorials]]></category>
		<guid isPermaLink="false">https://xlinesoft.com/blog/?p=3222</guid>

					<description><![CDATA[In this article we will discuss how to minimize the amount of code that handles Javascript on Add/Edit pages. Making your code data-driven will help you easily manage forms with a huge numbers of fields. We will be taking care of functionality like showing/hiding fields, making fields readonly, required, disabled etc. This approach will involve the following steps 1. Creating and populating database tables to store triggers ( when to apply the logic ) and actions ( what happens when trigger goes off ) 2....<span class="clearfix clearfix-post"></span><a href="https://xlinesoft.com/blog/2025/09/04/moving-logic-from-javascript-to-the-database/" class="more-link">Continue Reading <span class="screen-reader-text">"Moving logic from Javascript to the database"</span> <span class="meta-nav">&#8594;</span></a>]]></description>
										<content:encoded><![CDATA[<p>In this article we will discuss how to minimize the amount of code that handles Javascript on Add/Edit pages. Making your code data-driven will help you easily manage forms with a huge numbers of fields. We will be taking care of functionality like showing/hiding fields, making fields readonly, required, disabled etc. </p>
<p>This approach will involve the following steps<br />
1. Creating and populating database tables to store triggers ( when to apply the logic ) and actions ( what happens when trigger goes off )<br />
2. Server-side PHP and C# code that passes this data to Javascript<br />
3. Javascript code itself that listens to &#8220;change&#8221; event and implements the logic defined in the database.</p>
<p><a href="https://xlinesoft.com/blog/wp-content/uploads/2025/09/f4e4f71c-f4d8-465c-8a1c-67dbe4d205b9.png"><img loading="lazy" decoding="async" src="https://xlinesoft.com/blog/wp-content/uploads/2025/09/f4e4f71c-f4d8-465c-8a1c-67dbe4d205b9-600x400.png" alt="" width="600" height="400" class="alignnone size-medium wp-image-3233" srcset="https://xlinesoft.com/blog/wp-content/uploads/2025/09/f4e4f71c-f4d8-465c-8a1c-67dbe4d205b9-600x400.png 600w, https://xlinesoft.com/blog/wp-content/uploads/2025/09/f4e4f71c-f4d8-465c-8a1c-67dbe4d205b9-1024x683.png 1024w, https://xlinesoft.com/blog/wp-content/uploads/2025/09/f4e4f71c-f4d8-465c-8a1c-67dbe4d205b9-768x512.png 768w, https://xlinesoft.com/blog/wp-content/uploads/2025/09/f4e4f71c-f4d8-465c-8a1c-67dbe4d205b9.png 1536w" sizes="(max-width: 600px) 100vw, 600px" /></a><br />
<span id="more-3222"></span></p>
<h3>Database tables</h3>
<p>Triggers table. The structure is fairly simple. You can see that we store table name, page type, field name and what event we are listening to. In this article we will only show how to implement the most common &#8220;change&#8221; event as it covers 95% of required functionality. </p>
<p><a href="https://xlinesoft.com/blog/wp-content/uploads/2025/09/triggers.png"><img loading="lazy" decoding="async" src="https://xlinesoft.com/blog/wp-content/uploads/2025/09/triggers-600x104.png" alt="" width="600" height="104" class="alignnone size-medium wp-image-3226" srcset="https://xlinesoft.com/blog/wp-content/uploads/2025/09/triggers-600x104.png 600w, https://xlinesoft.com/blog/wp-content/uploads/2025/09/triggers.png 632w" sizes="(max-width: 600px) 100vw, 600px" /></a></p>
<p>Actions table is a details one while triggers is a master. They are linked by trigger_id field. This table knows what condition to check and what action to perform. Lets take a look at the first row and try to decipher it.</p>
<p>The action is tied to trigger #1 ( change event of Country field on the Edit page of customers table). The condition is equal and the condition_value is &#8216;USA&#8217;. Which means that when Country field equals &#8216;USA&#8217; we should proceed with our action. And the action itself is showing of the Region field. </p>
<p><a href="https://xlinesoft.com/blog/wp-content/uploads/2025/09/actions.png"><img loading="lazy" decoding="async" src="https://xlinesoft.com/blog/wp-content/uploads/2025/09/actions-600x269.png" alt="" width="600" height="269" class="alignnone size-medium wp-image-3225" srcset="https://xlinesoft.com/blog/wp-content/uploads/2025/09/actions-600x269.png 600w, https://xlinesoft.com/blog/wp-content/uploads/2025/09/actions-768x345.png 768w, https://xlinesoft.com/blog/wp-content/uploads/2025/09/actions.png 789w" sizes="(max-width: 600px) 100vw, 600px" /></a></p>
<p>And here is the SQL script that will create both tables for you with sample data.</p>
<div class="my-syntax-highlighter">
<pre><textarea id="mshighlighter" class="mshighlighter" language="sql" name="mshighlighter" >
CREATE TABLE IF NOT EXISTS `actions` (
  `id` int NOT NULL AUTO_INCREMENT,
  `condition` varchar(250) DEFAULT NULL,
  `target` varchar(250) DEFAULT NULL,
  `action` varchar(250) DEFAULT NULL,
  `condition_value` varchar(250) DEFAULT NULL,
  `trigger_id` int DEFAULT NULL,
  KEY `Index 1` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

INSERT INTO `actions` (`id`, `condition`, `target`, `action`, `condition_value`, `trigger_id`) VALUES
	(1, 'equals', 'Region', 'show', 'USA', 1),
	(2, 'empty', 'ContactTitle', 'hide', NULL, 2),
	(3, 'notepmty', 'ContactTitle', 'readonly', NULL, 2),
	(4, 'notempty', 'ContactTitle', 'show', NULL, 2),
	(5, 'notequals', 'Region', 'hide', 'USA', 1),
	(6, 'notempty', 'Fax', 'disable', NULL, 2),
	(7, 'empty', 'Fax', 'enable', NULL, 2),
	(8, 'equals', 'Region', 'clear', 'USA', 1),
	(9, 'equals', 'Region', 'focus', 'USA', 1),
	(10, 'equals', 'Region', 'require', 'USA', 1);

CREATE TABLE IF NOT EXISTS `triggers` (
  `id` int NOT NULL AUTO_INCREMENT,
  `table` varchar(250) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `page` varchar(250) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `event` varchar(50) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `field` varchar(50) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

INSERT INTO `triggers` (`id`, `table`, `page`, `event`, `field`) VALUES
	(1, 'customers', 'edit', 'change', 'Country'),
	(2, 'customers', 'edit', 'change', 'ContactName');</textarea></pre>
</div>
<h3>Server-side code</h3>
<p>Server-side code goes to <strong>BeforeDisplay event</strong> of each page where this functionality needs to be implemented. In our situation this code goes to BeforeDisplay event of Customers table Edit page. The code itself is fairly straightforward. It just dumps all the data from actions and triggers tables and makes this data available in Javascript via proxy object. </p>
<p>Note that for better code structure you need to create an external PHP or C# file, define a function there and place this code into that function. Then in all BeforeDisplay events </p>
<p><strong>PHP code</strong></p>
<div class="my-syntax-highlighter">
<pre><textarea id="mshighlighter" class="mshighlighter" language="php" name="mshighlighter" >
$table = $pageObject->tName;
$page = $pageObject->pageName;

// get all the triggers for the current page and send it to Javascript
$sql = DB::PrepareSQL("select * from triggers WHERE `table`=':1' and page=':2'",
    $table, $page);

$triggers=array();

$rs = DB::Query($sql);
while( $data = $rs->fetchAssoc() )
{
    $triggers[] = $data;
}

// do the same for actions table

$sql = DB::PrepareSQL("SELECT * FROM actions WHERE trigger_id IN (select id from triggers WHERE `table`=':1' and page=':2'",
    $table, $page);

$actions=array();

$rs = DB::Query($sql);
while( $data = $rs->fetchAssoc() )
{
    $actions[] = $data;
}

$pageObject->setProxyValue("triggers", $triggers);
$pageObject->setProxyValue("actions", $actions);</textarea></pre>
</div>
<p><strong>C# code</strong></p>
<div class="my-syntax-highlighter">
<pre><textarea id="mshighlighter" class="mshighlighter" language="" name="mshighlighter" >
dynamic actions = XVar.Array(), page = null, sql = null, triggers = XVar.Array();
table = XVar.Clone(pageObject.tName);
page = XVar.Clone(pageObject.pageName);
sql = XVar.Clone(DB.PrepareSQL(new XVar("select * from triggers WHERE `table`=':1' and page=':2'"), (XVar)(table), (XVar)(page)));
triggers = XVar.Clone(XVar.Array());
rs = XVar.Clone(DB.Query((XVar)(sql)));
while(XVar.Pack(data = XVar.Clone(rs.fetchAssoc())))
	{
	triggers.InitAndSetArrayItem(data, null);
	}
sql = XVar.Clone(DB.PrepareSQL(new XVar("SELECT * FROM actions WHERE trigger_id IN (select id from triggers WHERE `table`=':1' and page=':2'"), (XVar)(table), (XVar)(page)));
actions = XVar.Clone(XVar.Array());
rs = XVar.Clone(DB.Query((XVar)(sql)));
while(XVar.Pack(data = XVar.Clone(rs.fetchAssoc())))
	{
	actions.InitAndSetArrayItem(data, null);
	}
pageObject.setProxyValue(new XVar("triggers"), (XVar)(triggers));
pageObject.setProxyValue(new XVar("actions"), (XVar)(actions));
return null;</textarea></pre>
</div>
<h3>Javascript code</h3>
<p>Javascript code goes to Javascript OnLoad event of the page where the action should happen, in our case this is Javascript OnLoad event of Customers table Edit page. The same idea with creating a Javascript function and calling from the external file is also valid here. </p>
<p>You can extend this code by adding more conditions types and more actions. Check inline comments for more info. </p>
<div class="my-syntax-highlighter">
<pre><textarea id="mshighlighter" class="mshighlighter" language="javascript" name="mshighlighter" >
$('input, textarea, select, radio').on('change', function() {
        // 'this' refers to the element that triggered the change event
        const str = $(this).attr('id');
        const match = str.match(/^value_(.*?)_/);
        var name;
        if (match) {
            console.log('Value changed for:', match[1] , 'New value:', $(this).val());
            name = match[1];
            value = $(this).val();
        }
        
        // lets see if we have a trigger associated with the current field
        let triggers = proxy['triggers'];
        let actions = proxy['actions'];
        for (const trigger of triggers) {
            if (trigger["field"]==name ) {
                // loop through actions array to see what kind of actions we need to perform
                for (const action of actions) {
                    if ( trigger["id"] == action["trigger_id"]) {
                        
                        var proceed = false;
                        
                        // check conditions
                        // equals
                        if (action["condition"] == "equals") {
                            if ( action["condition_value"] == value ) {
                                proceed = true;
                            }
                        }
                        // not equals
                        if (action["condition"] == "notequals") {
                            if ( action["condition_value"] != value ) {
                                proceed = true;
                            }
                        }
                        // empty
                        if (action["condition"] == "empty") {
                            if ( value.length==0 ) {
                                proceed = true;
                            }
                        }
                        // not empty
                        if (action["condition"] == "notempty") {
                            if ( value.length!=0 ) {
                                proceed = true;
                            }
                        }
                        
                        // do we have mathcing conditions 
                        
                        if (proceed) {
                            // show action
                            if (action["action"] == "show") {
                                pageObj.showField(action["target"]);
                            }

                            // hide action
                            if (action["action"] == "hide") {
                                pageObj.hideField(action["target"]);
                            }
                            // clear action
                            if (action["action"] == "clear") {
                                Runner.getControl(pageid, action["target"]).setValue();
                            }
                            // focus action
                            if (action["action"] == "focus") {
                                Runner.getControl(pageid, action["target"]).setFocus();
                            }
                            // require action
                            if (action["action"] == "require") {
                                Runner.getControl(pageid, action["target"]).addValidation("IsRequired");
                            }
                            
                        }

                    }
                }
            }
        }    
    });</textarea></pre>
</div>
<p>Enjoy!</p>
]]></content:encoded>
					
					<wfw:commentRss>https://xlinesoft.com/blog/2025/09/04/moving-logic-from-javascript-to-the-database/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>Version 11.1 release</title>
		<link>https://xlinesoft.com/blog/2025/06/17/version-11-1-release/</link>
					<comments>https://xlinesoft.com/blog/2025/06/17/version-11-1-release/#comments</comments>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Tue, 17 Jun 2025 16:04:51 +0000</pubDate>
				<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[News]]></category>
		<category><![CDATA[PHP]]></category>
		<guid isPermaLink="false">https://xlinesoft.com/blog/?p=3189</guid>

					<description><![CDATA[Version 11.1 release is here! Is is available for both PHPRunner (Windows, Mac, Linux) and ASPRunner.NET. Version 11 most frequently asked questions answered. To download a registered version logon to your control panel account and find download links under &#8216;My purchases&#8217;. Trial version download links PHPRunner 11.1 for Windows trial &#160;&#160; ASPRunner.NET 11.1 for Windows trial PHPRunner 11.1 for Mac trial PHPRunner 11.1 for Linux (Debian) trial PHPRunner 11.1 for Linux (RedHat) trial You can install and run it side by side with versions 10.x...<span class="clearfix clearfix-post"></span><a href="https://xlinesoft.com/blog/2025/06/17/version-11-1-release/" class="more-link">Continue Reading <span class="screen-reader-text">"Version 11.1 release"</span> <span class="meta-nav">&#8594;</span></a>]]></description>
										<content:encoded><![CDATA[<p>Version 11.1 release is here! Is is available for both PHPRunner (Windows, Mac, Linux) and ASPRunner.NET. </p>
<p><a href="https://asprunner.com/forums/topic/30499-Version-11-Frequently-Asked-Questions">Version 11 most frequently asked questions answered</a>.</p>
<p>To download a registered version logon to your <a href='https://xlinesoft.com/dss/support.php'>control panel</a> account and find download links under &#8216;My purchases&#8217;.</p>
<h3>Trial version download links</h3>
<p><a href="https://asprunner.com/files/phprunner-trial.exe" class="btn_purple" style="color: white;" contenteditable="false" style="cursor: pointer;">PHPRunner 11.1 for Windows trial</a><br />
&nbsp;&nbsp;<br />
<a href="https://asprunner.com/files/asprunnernet-trial.exe" class="btn_purple" style="color: white;" contenteditable="false" style="cursor: pointer;">ASPRunner.NET 11.1 for Windows trial</a></p>
<p><a href="https://asprunner.com/files/phprunner-trial.dmg" class="btn_purple" style="color: white;" contenteditable="false" style="cursor: pointer;">PHPRunner 11.1 for Mac trial</a></p>
<p><a href="https://asprunner.com/files/phprunner-trial.deb" class="btn_purple" style="color: white;" contenteditable="false" style="cursor: pointer;">PHPRunner 11.1 for Linux (Debian) trial</a></p>
<p><a href="https://asprunner.com/files/phprunner-trial.rpm" class="btn_purple" style="color: white;" contenteditable="false" style="cursor: pointer;">PHPRunner 11.1 for Linux (RedHat) trial</a></p>
<p>You can install and run it side by side with versions 10.x and 11.0. Existing software functionality will not be affected. Just make sure you do not launch v11 and v11.1 at the same time if you use a built-in database to store projects. </p>
<h3>New features in v11.1</h3>
<ul>
<li>Calendar View</li>
<li>GANTT View</li>
<li>Source control systems support ( SVN, git )</li>
<li>Lookup wizard enhancements</li>
</ul>
<p><span id="more-3189"></span></p>
<h3>Calendar View</h3>
<p>When you launch version 11.1 you notice two new buttons on the toolbar, &#8216;Create Calendar&#8217; and &#8216;Create GANTT chart&#8217;. Click &#8216;Create Calendar&#8217;. Choose to create a new table to get familiar with this feature. You can switch to using your own database table later. The software will create a new table for you and will even add some test data. You can now build the project and enjoy a fully-working Calendar page. </p>
<p><a href="https://xlinesoft.com/blog/wp-content/uploads/2025/06/calendar.png"><img loading="lazy" decoding="async" src="https://xlinesoft.com/blog/wp-content/uploads/2025/06/calendar-600x305.png" alt="" width="600" height="305" class="alignnone size-medium wp-image-3194" srcset="https://xlinesoft.com/blog/wp-content/uploads/2025/06/calendar-600x305.png 600w, https://xlinesoft.com/blog/wp-content/uploads/2025/06/calendar-1024x521.png 1024w, https://xlinesoft.com/blog/wp-content/uploads/2025/06/calendar-768x391.png 768w, https://xlinesoft.com/blog/wp-content/uploads/2025/06/calendar-1536x781.png 1536w, https://xlinesoft.com/blog/wp-content/uploads/2025/06/calendar.png 1827w" sizes="(max-width: 600px) 100vw, 600px" /></a></p>
<p>If you choose to use your own table make sure to proceed to &#8216;Calendar settings&#8217; screen ( between Pages and Fields ) and configure your Calendar. Date field and subject field are mandatory and rest are optional. </p>
<p>PS. Calendar view is based on FullCalendar open source project. </p>
<h3>GANTT View</h3>
<p>GANTT Chart is similar in many ways to the Calendar. We also recommend creating a new table and getting familiar with this feature first. GANTT View specific settings can be found on &#8216;Gantt&#8217; screen. </p>
<p><a href="https://xlinesoft.com/blog/wp-content/uploads/2025/06/gantt.png"><img loading="lazy" decoding="async" src="https://xlinesoft.com/blog/wp-content/uploads/2025/06/gantt-600x321.png" alt="" width="600" height="321" class="alignnone size-medium wp-image-3198" srcset="https://xlinesoft.com/blog/wp-content/uploads/2025/06/gantt-600x321.png 600w, https://xlinesoft.com/blog/wp-content/uploads/2025/06/gantt-1024x547.png 1024w, https://xlinesoft.com/blog/wp-content/uploads/2025/06/gantt-768x410.png 768w, https://xlinesoft.com/blog/wp-content/uploads/2025/06/gantt.png 1319w" sizes="(max-width: 600px) 100vw, 600px" /></a></p>
<p>You can add, edit, delete tasks, add dependent tasks, use drag-n-drop to change task/subtask dates or update task progress. </p>
<p>PS. We use Frappe Gantt component as a core of this new feature. </p>
<h3>SVN/git support</h3>
<p>Source control system support provides two main scenarios.<br />
1. Using SVN/git for backups only.<br />
2. Single developer working on the same project from different machines. </p>
<p><strong>SVN, backup only</strong></p>
<p>1. Install SVN command-line client software. On Windows we recommend <a href="https://sliksvn.com/download/">SilkSVN</a>. </p>
<p>2. Create a new empty folder in your SVN repository. Checkout it to any folder on your local computer. </p>
<p>3. In PHPRunner/ASPRunner.NET proceed to Project -> Version control settings and select &#8216;Export directory&#8217;, the same one where you performed the checkout. Other settings will be populated automatically.</p>
<p>4. &#8216;Commit after each project saving&#8217; &#8211; this is up to you to decide.</p>
<p>5. &#8216;Update on each project opening&#8217; &#8211; if you use SVN for backups only then turn this option off.  </p>
<p>Once you performed these steps, you will see a new &#8216;Save and commit&#8217; button at the bottom of the software. Use it to save your project and commit changes to repository. </p>
<p>6. To restore a project from backup proceed to the start screen of the software, &#8216;Import&#8217; tab. Click Browse and point the software to project.json file in the checkout folder.</p>
<p><a href="https://xlinesoft.com/blog/wp-content/uploads/2025/06/svn.png"><img loading="lazy" decoding="async" src="https://xlinesoft.com/blog/wp-content/uploads/2025/06/svn-600x497.png" alt="" width="600" height="497" class="alignnone size-medium wp-image-3204" srcset="https://xlinesoft.com/blog/wp-content/uploads/2025/06/svn-600x497.png 600w, https://xlinesoft.com/blog/wp-content/uploads/2025/06/svn.png 726w" sizes="(max-width: 600px) 100vw, 600px" /></a></p>
<p><strong>SVN, working from different computers</strong></p>
<p>1. On the first computer repeat all steps for &#8216;Backup only&#8217;. Enable option &#8216;Update on each project opening&#8217;. Now, in order to open this project you will need to use &#8216;Open from version control&#8217; tab on the start screen. </p>
<p>2. On the second computer perform project checkout from SVN. On start screen proceed to &#8216;Open from version control&#8217; tab, click Browse and point it to the folder where you performed the checkout. You will see a dialog with SVN settings, just leave everything as is and click &#8216;OK&#8217;. </p>
<p><strong>Note:</strong> it is important not to use this feature for simultaneous development by multiple developers. Each commit will override changes made on another computer. </p>
<p><strong>GIT</strong></p>
<p>The ideology is the same but there a few extra commands you need to execute manually. </p>
<p>1. Create a new repository at <a href="https://github.com/">github.com</a>, for example JonDoe/Cars</p>
<p>2. Create a directory on your computer, open the terminal and change to that directory.</p>
<p>3. Run these commands, replace <strong>JonDoe/Cars</strong> with the actual repository name:</p>
<div class="my-syntax-highlighter">
<pre><textarea id="mshighlighter" class="mshighlighter" language="" name="mshighlighter" >
git init
git remote add origin https://github.com/JonDoe/Cars.git
git branch -M main</textarea></pre>
</div>
<p>4. Repeat steps 2 and 3 to access your github repository on the second computer.</p>
<p>5. During the first Save and Commit you may encounter this error:</p>
<div class="my-syntax-highlighter">
<pre><textarea id="mshighlighter" class="mshighlighter" language="" name="mshighlighter" >
Author identity unknown
*** Please tell me who you are.</textarea></pre>
</div>
<p>If this happens, run the following commands in the terminal/command line and and try saving and committing again.</p>
<div class="my-syntax-highlighter">
<pre><textarea id="mshighlighter" class="mshighlighter" language="" name="mshighlighter" >
git config --global user.email "you@example.com"
git config --global user.name "Your Name"</textarea></pre>
</div>
<p>6. Now you can do the same, in PHPRunner/ASPRunner.NET proceed to &#8216;Open from version control&#8217; tab, click Browse and point it to the folder where you performed the checkout.</p>
<h3>Lookup Wizard enhancements</h3>
<p>New feature here is &#8216;Edit selected&#8217; which allows you to edit selected entry in a lookup wizard. Can be handy when you noticed a typo in Lookup Wizard data and want to fix it without leaving the page. </p>
<p><a href="https://xlinesoft.com/blog/wp-content/uploads/2025/06/lookupwizard.png"><img loading="lazy" decoding="async" src="https://xlinesoft.com/blog/wp-content/uploads/2025/06/lookupwizard-600x437.png" alt="" width="600" height="437" class="alignnone size-medium wp-image-3201" srcset="https://xlinesoft.com/blog/wp-content/uploads/2025/06/lookupwizard-600x437.png 600w, https://xlinesoft.com/blog/wp-content/uploads/2025/06/lookupwizard-1024x746.png 1024w, https://xlinesoft.com/blog/wp-content/uploads/2025/06/lookupwizard-768x559.png 768w, https://xlinesoft.com/blog/wp-content/uploads/2025/06/lookupwizard.png 1056w" sizes="(max-width: 600px) 100vw, 600px" /></a></p>
<p>Enjoy!</p>
]]></content:encoded>
					
					<wfw:commentRss>https://xlinesoft.com/blog/2025/06/17/version-11-1-release/feed/</wfw:commentRss>
			<slash:comments>7</slash:comments>
		
		
			</item>
		<item>
		<title>Running PHPRunner application as a Docker container</title>
		<link>https://xlinesoft.com/blog/2025/05/07/running-phprunner-application-as-a-docker-container/</link>
					<comments>https://xlinesoft.com/blog/2025/05/07/running-phprunner-application-as-a-docker-container/#comments</comments>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Wed, 07 May 2025 15:35:28 +0000</pubDate>
				<category><![CDATA[News]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[PHP Code Generator]]></category>
		<category><![CDATA[Tutorials]]></category>
		<guid isPermaLink="false">https://xlinesoft.com/blog/?p=3145</guid>

					<description><![CDATA[What is Docker? Docker is a software platform that allows you to package, distribute, and run applications within self-contained units called containers. These containers include everything the application needs, like code, runtime, and libraries, ensuring consistent execution across different environments. How this can be useful? There are many possible uses of Docker containers. You can use them for testing for instance. If you have a website that runs on PHP 8.1 and want to make sure that switching to PHP 8.3 doesn&#8217;t break anything, you...<span class="clearfix clearfix-post"></span><a href="https://xlinesoft.com/blog/2025/05/07/running-phprunner-application-as-a-docker-container/" class="more-link">Continue Reading <span class="screen-reader-text">"Running PHPRunner application as a Docker container"</span> <span class="meta-nav">&#8594;</span></a>]]></description>
										<content:encoded><![CDATA[<p>What is Docker? Docker is a software platform that allows you to package, distribute, and run applications within self-contained units called containers. These containers include everything the application needs, like code, runtime, and libraries, ensuring consistent execution across different environments. </p>
<p>How this can be useful? There are many possible uses of Docker containers. You can use them for testing for instance. If you have a website that runs on PHP 8.1 and want to make sure that switching to PHP 8.3 doesn&#8217;t break anything, you can create a container based on PHP 8.3 and fully test your app there before making a switch on the main website. Other options include distributing your application to your customers as a container or using containers for web hosting if your web hosting provider supports this option.  </p>
<p>In this article we will explain how you can package your PHPRunner application as a Docker container. </p>
<h3>Docker Desktop installation</h3>
<p>As a first step you need to install Docker Desktop on your local computer. Just download it from the <a href="https://www.docker.com/products/docker-desktop/">official website</a> and install keeping all default settings. </p>
<p>Once Docker Desktop is installed, launch it. Two main sections we are going to work with are <strong>Images</strong> and <strong>Containers</strong>. </p>
<p>A Docker image is a read-only template that contains everything needed to run an application, including the application&#8217;s code, system tools, and libraries. A Docker container is a running instance of a Docker image Think of an image as a blueprint and a container as the building constructed from that blueprint. </p>
<h3>Project structure</h3>
<p>Create a new folder for our Docker project i.e. C:\Project\Docker. Here is how the default Docker project looks like. <strong>src</strong> folder needs to be created manually and this is where all our PHP files will be stored. Luckily, we do not need to create the rest of file manually, Docker desktop can help us creating those. </p>
<p><a href="https://xlinesoft.com/blog/wp-content/uploads/2025/04/project_structure.png"><img loading="lazy" decoding="async" src="https://xlinesoft.com/blog/wp-content/uploads/2025/04/project_structure-600x358.png" alt="" width="600" height="358" class="alignnone size-medium wp-image-3152" srcset="https://xlinesoft.com/blog/wp-content/uploads/2025/04/project_structure-600x358.png 600w, https://xlinesoft.com/blog/wp-content/uploads/2025/04/project_structure-768x458.png 768w, https://xlinesoft.com/blog/wp-content/uploads/2025/04/project_structure.png 965w" sizes="(max-width: 600px) 100vw, 600px" /></a></p>
<h3>Docker init</h3>
<p>Start by opening a terminal ( click Terminal icon in the bottom right corner ). First, switch to your project folder and then run <strong>docker init</strong> command. </p>
<div class="my-syntax-highlighter">
<pre><textarea id="mshighlighter" class="mshighlighter" language="php" name="mshighlighter" >
cd C:\Projects\Docker

docker init</textarea></pre>
</div>
<p>Docker will ask you a few questions about what you want to create. Select Apache+PHP web application. You can use up and down keyboard keys to change your selection. Press Enter to make a choice.  </p>
<p><a href="https://xlinesoft.com/blog/wp-content/uploads/2025/05/docker_init.png"><img loading="lazy" decoding="async" src="https://xlinesoft.com/blog/wp-content/uploads/2025/05/docker_init-600x405.png" alt="" width="600" height="405" class="alignnone size-medium wp-image-3171" srcset="https://xlinesoft.com/blog/wp-content/uploads/2025/05/docker_init-600x405.png 600w, https://xlinesoft.com/blog/wp-content/uploads/2025/05/docker_init-1024x691.png 1024w, https://xlinesoft.com/blog/wp-content/uploads/2025/05/docker_init-768x518.png 768w, https://xlinesoft.com/blog/wp-content/uploads/2025/05/docker_init.png 1475w" sizes="(max-width: 600px) 100vw, 600px" /></a></p>
<p>For all other questions leave default options. Docker will create an image for you, based on your selection. On <strong>Images</strong> tab you are now going to see a new image. Docker will also tell you that now you need to run <strong>docker compose up &#8211;build</strong> command in order to build and launch your container. </p>
<p><a href="https://xlinesoft.com/blog/wp-content/uploads/2025/04/docker_after_init.png"><img loading="lazy" decoding="async" src="https://xlinesoft.com/blog/wp-content/uploads/2025/04/docker_after_init-600x392.png" alt="" width="600" height="392" class="alignnone size-medium wp-image-3150" srcset="https://xlinesoft.com/blog/wp-content/uploads/2025/04/docker_after_init-600x392.png 600w, https://xlinesoft.com/blog/wp-content/uploads/2025/04/docker_after_init-1024x669.png 1024w, https://xlinesoft.com/blog/wp-content/uploads/2025/04/docker_after_init-768x502.png 768w, https://xlinesoft.com/blog/wp-content/uploads/2025/04/docker_after_init.png 1415w" sizes="(max-width: 600px) 100vw, 600px" /></a></p>
<h3>Dockerfile</h3>
<p>This is how the initial <strong>dockerfile</strong> looks. I just removed some extra comments for brevity. Lets try to create a container and run it. </p>
<div class="my-syntax-highlighter">
<pre><textarea id="mshighlighter" class="mshighlighter" language="php" name="mshighlighter" >
# syntax=docker/dockerfile:1

# https://docs.docker.com/go/dockerfile-reference/

FROM php:8.2-apache

RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"

# Copy app files from the app directory.
COPY ./src /var/www/html

# Switch to a non-privileged user (defined in the base image) that the app will run under.
# See https://docs.docker.com/go/dockerfile-user-best-practices/
USER www-data</textarea></pre>
</div>
<h3>Build and first run</h3>
<p>Without making any changes to <strong>dockerfile</strong> we go back to the terminal and run the suggested build command:</p>
<div class="my-syntax-highlighter">
<pre><textarea id="mshighlighter" class="mshighlighter" language="php" name="mshighlighter" >
docker compose up –build</textarea></pre>
</div>
<p>First build will take about a minute and consecutive will be a bit faster. Dcker performs the build and starts our container. You can see container&#8217;s status on Containers tab. You can see that our new container is up and running. </p>
<p><a href="https://xlinesoft.com/blog/wp-content/uploads/2025/04/container_running.png"><img loading="lazy" decoding="async" src="https://xlinesoft.com/blog/wp-content/uploads/2025/04/container_running-600x402.png" alt="" width="600" height="402" class="alignnone size-medium wp-image-3149" srcset="https://xlinesoft.com/blog/wp-content/uploads/2025/04/container_running-600x402.png 600w, https://xlinesoft.com/blog/wp-content/uploads/2025/04/container_running-1024x686.png 1024w, https://xlinesoft.com/blog/wp-content/uploads/2025/04/container_running-768x515.png 768w, https://xlinesoft.com/blog/wp-content/uploads/2025/04/container_running.png 1343w" sizes="(max-width: 600px) 100vw, 600px" /></a></p>
<p>Which means we can can now open a web browser and type in the following URL: <strong>http://localhost:9000</strong>. This is what you are supposed to see:</p>
<p><a href="https://xlinesoft.com/blog/wp-content/uploads/2025/04/mysqli_missing.png"><img loading="lazy" decoding="async" src="https://xlinesoft.com/blog/wp-content/uploads/2025/04/mysqli_missing-600x371.png" alt="" width="600" height="371" class="alignnone size-medium wp-image-3151" srcset="https://xlinesoft.com/blog/wp-content/uploads/2025/04/mysqli_missing-600x371.png 600w, https://xlinesoft.com/blog/wp-content/uploads/2025/04/mysqli_missing-768x474.png 768w, https://xlinesoft.com/blog/wp-content/uploads/2025/04/mysqli_missing.png 955w" sizes="(max-width: 600px) 100vw, 600px" /></a></p>
<p>Good news: our container is in fact running.<br />
Bad news: mysqli extension is missing and we cannot connect to MySQL.</p>
<h3>Installing mysqli extension</h3>
<p>Quick Google search for &#8220;docker php install mysqli&#8221; points us to the solution and we modify our <strong>dockerfile</strong> in any text editor adding lines 7 and 8. </p>
<div class="my-syntax-highlighter">
<pre><textarea id="mshighlighter" class="mshighlighter" language="php" name="mshighlighter" >
# syntax=docker/dockerfile:1

# https://docs.docker.com/go/dockerfile-reference/

FROM php:8.2-apache

# this is the line we have added manually
RUN docker-php-ext-install mysqli

RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"

# Copy app files from the app directory.
COPY ./src /var/www/html

# Switch to a non-privileged user (defined in the base image) that the app will run under.
# See https://docs.docker.com/go/dockerfile-user-best-practices/
USER www-data</textarea></pre>
</div>
<p>Now we stop the container, run the build command again and once finished we refresh our browser window. This takes us one step further but we are not quite there yet. </p>
<p><a href="https://xlinesoft.com/blog/wp-content/uploads/2025/05/docker_mysql_connection_error.png"><img loading="lazy" decoding="async" src="https://xlinesoft.com/blog/wp-content/uploads/2025/05/docker_mysql_connection_error-600x342.png" alt="" width="600" height="342" class="alignnone size-medium wp-image-3181" srcset="https://xlinesoft.com/blog/wp-content/uploads/2025/05/docker_mysql_connection_error-600x342.png 600w, https://xlinesoft.com/blog/wp-content/uploads/2025/05/docker_mysql_connection_error-1024x584.png 1024w, https://xlinesoft.com/blog/wp-content/uploads/2025/05/docker_mysql_connection_error-768x438.png 768w, https://xlinesoft.com/blog/wp-content/uploads/2025/05/docker_mysql_connection_error-900x515.png 900w, https://xlinesoft.com/blog/wp-content/uploads/2025/05/docker_mysql_connection_error.png 1135w" sizes="(max-width: 600px) 100vw, 600px" /></a></p>
<p>While this error is not very descriptive we can guess that our application is not able to connect to MySQL. We use &#8220;localhost&#8221; as MySQL server address which in case of the container refers to container itself. We need to find a way to connect to MySQL on the host which is our local computer running Docker desktop. Another quick Google search for &#8220;docker connect to host from container&#8221; points us to <strong>host.docker.internal</strong> which we need to use instead of <strong>localhost</strong> while connecting to MySQL. </p>
<p>We proceed to PHPRunner, create a new Server Database Connection on the &#8216;Output Directory&#8217; screen and change the address of MySQL server as follows:</p>
<div class="my-syntax-highlighter">
<pre><textarea id="mshighlighter" class="mshighlighter" language="php" name="mshighlighter" >
$host = 'host.docker.internal';
$user = 'root';
$pwd = '';
$port = 3306;
$sys_dbname = 'cars';</textarea></pre>
</div>
<h3>And one more try</h3>
<p>1. Stop the container<br />
2. Build PHPRunner project ( make sure that new connection is selected )<br />
3. Copy all files from PHPRunner&#8217;s output folder to C:\Projects\Docker\src<br />
4. Execute <strong>docker compose up &#8211;build</strong> command one more time.<br />
5. Refresh browser&#8217;s window</p>
<p>It runs!</p>
<p><a href="https://xlinesoft.com/blog/wp-content/uploads/2025/05/docker_runs.png"><img loading="lazy" decoding="async" src="https://xlinesoft.com/blog/wp-content/uploads/2025/05/docker_runs-600x314.png" alt="" width="600" height="314" class="alignnone size-medium wp-image-3184" srcset="https://xlinesoft.com/blog/wp-content/uploads/2025/05/docker_runs-600x314.png 600w, https://xlinesoft.com/blog/wp-content/uploads/2025/05/docker_runs-1024x536.png 1024w, https://xlinesoft.com/blog/wp-content/uploads/2025/05/docker_runs-768x402.png 768w, https://xlinesoft.com/blog/wp-content/uploads/2025/05/docker_runs.png 1394w" sizes="(max-width: 600px) 100vw, 600px" /></a></p>
<p>Additional notes. You can make your container connect to any database. It can be a database that is a part of the same container ( though it is not recommended ), or a database running in another container or any external database server. All you need to do is to point the database connection to your database of choice. </p>
]]></content:encoded>
					
					<wfw:commentRss>https://xlinesoft.com/blog/2025/05/07/running-phprunner-application-as-a-docker-container/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title>PHPDesktop update</title>
		<link>https://xlinesoft.com/blog/2025/01/09/phpdesktop-update/</link>
					<comments>https://xlinesoft.com/blog/2025/01/09/phpdesktop-update/#comments</comments>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Fri, 10 Jan 2025 02:32:57 +0000</pubDate>
				<category><![CDATA[PHP]]></category>
		<guid isPermaLink="false">https://xlinesoft.com/blog/?p=3138</guid>

					<description><![CDATA[As you might know, we teamed up with PHPDesktop developer to bring it to the latest version of Chromium and PHP. Now we have PHPDesktop 130.1 at our disposal that runs PHP 8.3. It will be a part of PHPRunner 11 soon and meanwhile I will show you how to upgrade PHPDesktop in your PHPRunner 10.91 installation. 1. Download updated PHPDesktop. Unzip it to C:\Program Files\PHPRunner 10.91\DesktopApp keeping directory structure and overwriting existing files. 2. Download updated phprunnerapp-setup.iss file and replace the existing one in...<span class="clearfix clearfix-post"></span><a href="https://xlinesoft.com/blog/2025/01/09/phpdesktop-update/" class="more-link">Continue Reading <span class="screen-reader-text">"PHPDesktop update"</span> <span class="meta-nav">&#8594;</span></a>]]></description>
										<content:encoded><![CDATA[<p>As you might know, we teamed up with PHPDesktop developer to bring it to the latest version of Chromium and PHP. Now we have PHPDesktop 130.1 at our disposal that runs PHP 8.3. It will be a part of PHPRunner 11 soon and meanwhile I will show you how to upgrade PHPDesktop in your PHPRunner 10.91 installation.</p>
<p><a href="https://xlinesoft.com/blog/wp-content/uploads/2025/01/scr.png"><img loading="lazy" decoding="async" src="https://xlinesoft.com/blog/wp-content/uploads/2025/01/scr-600x449.png" alt="" width="600" height="449" class="alignnone size-medium wp-image-3140" srcset="https://xlinesoft.com/blog/wp-content/uploads/2025/01/scr-600x449.png 600w, https://xlinesoft.com/blog/wp-content/uploads/2025/01/scr-768x575.png 768w, https://xlinesoft.com/blog/wp-content/uploads/2025/01/scr.png 785w" sizes="(max-width: 600px) 100vw, 600px" /></a></p>
<p>1. Download updated <a href="https://drive.google.com/file/d/1DomS70RuUU-DxpZSRL2orNQmmvRgUlTl/view?usp=sharing">PHPDesktop</a>. Unzip it to C:\Program Files\PHPRunner 10.91\DesktopApp keeping directory structure and overwriting existing files.</p>
<p>2. Download updated <a href='https://xlinesoft.com/blog/wp-content/uploads/2025/01/phprunnerapp-setup.iss'>phprunnerapp-setup.iss</a> file and replace the existing one in C:\Program Files\PHPRunner 10.91\DesktopApp folder. </p>
<p>This is it! Now you can use PHPRunner 10.91 to build desktop apps that support PHP 8.3.  </p>
]]></content:encoded>
					
					<wfw:commentRss>https://xlinesoft.com/blog/2025/01/09/phpdesktop-update/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>Displaying website visitors on the map</title>
		<link>https://xlinesoft.com/blog/2024/01/03/displaying-website-visitors-on-the-map/</link>
					<comments>https://xlinesoft.com/blog/2024/01/03/displaying-website-visitors-on-the-map/#respond</comments>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Thu, 04 Jan 2024 01:43:29 +0000</pubDate>
				<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Tutorials]]></category>
		<guid isPermaLink="false">https://xlinesoft.com/blog/?p=3074</guid>

					<description><![CDATA[Our goal is to display website visitors on the map, similar to the screenshot below. We will convert their IP address to lat/lng coordinates and display those markers on OpenStreetMap map. To perform the conversion of IP addresses to lat/lng pairs we are going to use the geolocation data from ip2location.com. We will display users that were active in the last ten minutes. If the user had some activity in the last 60 seconds, their dot will be pulsing. There is also a YouTube video...<span class="clearfix clearfix-post"></span><a href="https://xlinesoft.com/blog/2024/01/03/displaying-website-visitors-on-the-map/" class="more-link">Continue Reading <span class="screen-reader-text">"Displaying website visitors on the map"</span> <span class="meta-nav">&#8594;</span></a>]]></description>
										<content:encoded><![CDATA[<p>Our goal is to display website visitors on the map, similar to the screenshot below.</p>
<p>We will convert their IP address to lat/lng coordinates and display those markers on OpenStreetMap map. To perform the conversion of IP addresses to lat/lng pairs we are going to use the geolocation data from <a href="https://ip2location.com">ip2location.com</a>.</p>
<p>We will display users that were active in the last ten minutes. If the user had some activity in the last 60 seconds, their dot will be pulsing.</p>
<p><a href="https://xlinesoft.com/blog/wp-content/uploads/2024/01/interactive_map.png"><img loading="lazy" decoding="async" src="https://xlinesoft.com/blog/wp-content/uploads/2024/01/interactive_map-600x288.png" alt="" width="600" height="288" class="alignnone size-medium wp-image-3075" srcset="https://xlinesoft.com/blog/wp-content/uploads/2024/01/interactive_map-600x288.png 600w, https://xlinesoft.com/blog/wp-content/uploads/2024/01/interactive_map-1024x491.png 1024w, https://xlinesoft.com/blog/wp-content/uploads/2024/01/interactive_map-768x368.png 768w, https://xlinesoft.com/blog/wp-content/uploads/2024/01/interactive_map.png 1471w" sizes="(max-width: 600px) 100vw, 600px" /></a><br />
<span id="more-3074"></span></p>
<p>There is also a <a href="https://youtu.be/Xb5vmbVPe_g">YouTube video</a> that provides more details of this project.</p>
<p>1. Database structure. </p>
<p>We are going to need two tables, &#8216;users&#8217; and &#8216;ip2location&#8217;. The following is the script for MySQL database. </p>
<div class="my-syntax-highlighter">
<pre><textarea id="mshighlighter" class="mshighlighter" language="sql" name="mshighlighter" >
CREATE TABLE `ip2location`(`id` int NOT NULL AUTO_INCREMENT, `ip_start` decimal(20,6) NULL, `ip_end` decimal(20,6) NULL, `STATE` varchar(50) NULL, `COUNTRY` varchar(50) NULL, `REGION` varchar(50) NULL, `CITY` varchar(100) NULL, `LATITUDE` double NULL, `LONGITUDE` double NULL, PRIMARY KEY (`id`))CHARACTER SET utf8;
CREATE TABLE `users`(`id` int NOT NULL AUTO_INCREMENT, `ip` varchar(50) NOT NULL DEFAULT '0', `lat` double NOT NULL DEFAULT 0, `lng` double NOT NULL DEFAULT 0, `last_activity` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', PRIMARY KEY (`id`))CHARACTER SET utf8;</textarea></pre>
</div>
<p>Please note that this SQL script only creates &#8216;ip2location&#8217; but doesn&#8217;t come with the data. The data set itself is about 300Mb and you can download it for free at https://lite.ip2location.com/database/ip-country.</p>
<p>2. Insert a code snippet into a page where you want to display the map. In our case it would be the menu page. The code itself is very simple, it merely outputs the div with &#8216;map&#8217; ID. </p>
<p><strong>PHP code:</strong></p>
<div class="my-syntax-highlighter">
<pre><textarea id="mshighlighter" class="mshighlighter" language="php" name="mshighlighter" >
echo "<div id='map' style=''></div>";</textarea></pre>
</div>
<p>3. AfterApplicationInitialized event</p>
<p><strong>PHP code:</strong></p>
<div class="my-syntax-highlighter">
<pre><textarea id="mshighlighter" class="mshighlighter" language="php" name="mshighlighter" >

// convert IP address to a decimal number in order to perform a database search
function ip_to_decimal($ip_address) {
    $parts = explode('.', $ip_address);
    $decimal_ip = 0;
    foreach ($parts as $part) {
        $decimal_ip = $decimal_ip * 256 + (int) $part;
    }
    return $decimal_ip;
}

function saveCurrentUserData(){
		$ip = $_SERVER["REMOTE_ADDR"];
		if( empty($ip) )
			return false;
		$userRs = DB::Select("users",array("ip" => $ip));
		$user = $userRs->fetchAssoc();
		if( $user ){
			DB::Update("users", array("last_activity" => date("Y-m-d H:i:s")) ,array("ip" => $ip));
		}
		else{
			$decimalip = ip_to_decimal($ip);
			$coordsRs = DB::Query("select * from ip2location where ".$decimalip." BETWEEN ip_start and ip_end");

			$coords = $coordsRs->fetchAssoc();
			if( $coords ){
				$userData = array("ip" => $ip,
                                            "lat" => $coords["LATITUDE"], 
                                            "lng" =>  $coords["LONGITUDE"],
                                             "last_activity" => date("Y-m-d H:i:s"));
				DB::Insert("users",$userData);
			}
		}
}
if( postvalue("getActiveUsers") ){
	$interval = 10;  
        // we only display on the map users that accessed any page in the last ten minutes

	saveCurrentUserData();
	$dateCondition = date("Y-m-d H:i:s",time() - ($interval*60));
	$userRs = DB::Query("select * from users where last_activity > '".$dateCondition."'");
	$latLng = array();

        $userData = $userRs->fetchAssoc();
	while( $userData ){
		$coordsInfo = array("id" => $userData['id'], 
                              "lat" => $userData['lat'],
                              "lng" => $userData['lng'],
                               "active" => false);

		if( ( time() - strtotime($userData["last_activity"]) ) <=60 ) {
		    $coordsInfo['active'] = true;
                }
		$latLng[] = $coordsInfo;
                $userData = $userRs->fetchAssoc();
	}
	echo my_json_encode($latLng);
	exit();
}</textarea></pre>
</div>
<p>4. custom_function.js </p>
<p>The following Javascript code goes to Event Editor -> custom_function.js section. </p>
<pre>
$(document).ready(function() {

    $("#map").width($(".r-fluid").width());
    var height = $(window).height() - $("#map").offset().top - 30;
    $("#map").height(height);

    window.mapObj = new OpenLayers.Map("map", {
        controls: [
            new OpenLayers.Control.PanZoomBar(),

            new OpenLayers.Control.Navigation()
        ],
    });

    var layer = new OpenLayers.Layer.OSM();

    mapObj.addLayer(layer);

    window.markersList = new OpenLayers.Layer.Markers("Markers");
    mapObj.addLayer(markersList);
    mapObj.zoomToMaxExtent();

    updateMarkers();
    setInterval(updateMarkers, 5000);

    function updateMarkers() {

        $.post("", {
            getActiveUsers: true
        }, function(response) {

            var coordsArr = JSON.parse(response),
                activeIds = coordsArr.map(function(coords) {
                    return coords.id;
                }),
                allIds = markersList.markers.map(function(marker) {
                    return marker.id;
                });


            $.each(coordsArr, function(i, latLon) {

                if (!allIds.includes(latLon.id)) {
                    addMarker(latLon.id, latLon.lat, latLon.lng, latLon.active);
                } else {
                    var curMarker = markersList.markers.find(function(marker) {
                        return marker.id == latLon.id
                    });
                    if (curMarker.active != latLon.active) {
                        $(curMarker.icon.imageDiv).toggleClass("active", latLon.active);
                    }
                }
            });
            allIds = markersList.markers.map(function(marker) {
                return marker.id;
            });

            for (var i = 0; i < allIds.length; i++) {

                if (allIds[i] != undefined &#038;&#038; !activeIds.includes(allIds[i])) {

                    var markerToRemove = markersList.markers.find(function(marker) {
                        return marker.id == allIds[i]
                    });
                    markersList.removeMarker(markerToRemove);
                }

            }

            function addMarker(id, lat, lng, active) {

                var lonLat = new OpenLayers.LonLat(lng, lat)
                    .transform(
                        new OpenLayers.Projection("EPSG:4326"), // transform from WGS 1984
                        mapObj.getProjectionObject() // to Spherical Mercator Projection
                    );
                var icon = new OpenLayers.Icon("", new OpenLayers.Size(15, 15));
                var marker = new OpenLayers.Marker(lonLat, icon);
                if (active) {
                    $(marker.icon.imageDiv).addClass("active");
                }

                marker.id = id;
                marker.active = active;
                markersList.addMarker(marker);

                return marker;
            }
        });


    }
    updateMarkers();


});
</pre>
<p>5. CSS code ( Style Editor -> Modify CSS )</p>
<p>We use this CSS code to customize and prettify the default look of OSM map. </p>
<div class="my-syntax-highlighter">
<pre><textarea id="mshighlighter" class="mshighlighter" language="css" name="mshighlighter" >
.olTileImage {
    filter: brightness(48%) contrast(256%);
}

[id^="OL_Icon"] .olAlphaImg {
    background: white;
    cursor: pointer;
    border-radius: 100%;
  }
  [id^="OL_Icon"].active .olAlphaImg {
    animation: pulse 2s infinite;
    box-shadow: 10px 10px 10px rgba(255,255,255, 0.7);
    width:20px !important;
    height: 20px !important;
  }

  @-webkit-keyframes pulse {
    0% {
      -webkit-box-shadow: 10px 10px 10px rgba(255,255,255, 0.7);
    }
    70% {
        -webkit-box-shadow: 0 0 0 10px rgba(255,255,255, 0);
    }
    100% {
        -webkit-box-shadow: 0 0 0 0 rgba(255,255,255, 0);
    }
  }
  @keyframes pulse {
    0% {
      -moz-box-shadow: 0 0 0 0 rgba(255,255,255, 0.7);
      box-shadow: 0 0 0 0 rgba(255,255,255, 0.7);
    }
    70% {
        -moz-box-shadow: 0 0 0 10px rgba(255,255,255, 0);
        box-shadow: 0 0 0 10px rgba(255,255,255, 0);
    }
    100% {
        -moz-box-shadow: 0 0 0 0 rgba(255,255,255, 0);
        box-shadow: 0 0 0 0 rgba(255,255,255, 0);
    }
  }</textarea></pre>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://xlinesoft.com/blog/2024/01/03/displaying-website-visitors-on-the-map/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Clickable code snippet in a dashboard</title>
		<link>https://xlinesoft.com/blog/2023/12/19/clickable-code-snippet-in-a-dashboard/</link>
					<comments>https://xlinesoft.com/blog/2023/12/19/clickable-code-snippet-in-a-dashboard/#respond</comments>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Wed, 20 Dec 2023 02:03:56 +0000</pubDate>
				<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Tutorials]]></category>
		<guid isPermaLink="false">https://xlinesoft.com/blog/?p=3061</guid>

					<description><![CDATA[In this article we will show how you can easily create a clickable code snippet in a dashboard. Our snippet will display a number of customers in Customers table and clicking anywhere in snippet area will take us to the Customers table in question. 1. Add a code snippet to the dashboard. Use the following code. This is just a sample code and you can replace it with any code of your choice. PHP $header = "Number of customers"; $number = DB::DBLookup("select count(*) from customers");...<span class="clearfix clearfix-post"></span><a href="https://xlinesoft.com/blog/2023/12/19/clickable-code-snippet-in-a-dashboard/" class="more-link">Continue Reading <span class="screen-reader-text">"Clickable code snippet in a dashboard"</span> <span class="meta-nav">&#8594;</span></a>]]></description>
										<content:encoded><![CDATA[<p>In this article we will show how you can easily create a clickable code snippet in a dashboard. Our snippet will display a number of customers in <strong>Customers</strong> table and clicking anywhere in snippet area will take us to the <strong>Customers</strong> table in question. </p>
<p><img loading="lazy" decoding="async" src="https://xlinesoft.com/blog/wp-content/uploads/2023/12/dashboard_snippet-600x308.png" alt="" width="600" height="308" class="alignnone size-medium wp-image-3063" srcset="https://xlinesoft.com/blog/wp-content/uploads/2023/12/dashboard_snippet-600x308.png 600w, https://xlinesoft.com/blog/wp-content/uploads/2023/12/dashboard_snippet-768x394.png 768w, https://xlinesoft.com/blog/wp-content/uploads/2023/12/dashboard_snippet.png 989w" sizes="(max-width: 600px) 100vw, 600px" /><br />
<span id="more-3061"></span></p>
<p>1. Add a code snippet to the dashboard. Use the following code. This is just a sample code and you can replace it with any code of your choice.</p>
<p><strong>PHP</strong></p>
<div class="my-syntax-highlighter">
<pre><textarea id="mshighlighter" class="mshighlighter" language="php" name="mshighlighter" >
$header = "Number of customers";
$number = DB::DBLookup("select count(*) from customers");
echo "Customers in the database: ".$number;</textarea></pre>
</div>
<p><strong>C#</strong></p>
<div class="my-syntax-highlighter">
<pre><textarea id="mshighlighter" class="mshighlighter" language="" name="mshighlighter" >
dynamic number = null;
header = new XVar("Number of customers");
number = XVar.Clone(DB.DBLookup(new XVar("select count(*) from customers")));
MVCFunctions.Echo(MVCFunctions.Concat("Customers in the database: ", number));</textarea></pre>
</div>
<p>2. Build and run your application. Proceed to the dashboard page, right click on that snippet and choose &#8216;Inspect&#8217;. What we are looking for an ID of the DIV that encloses our code snippet. In our case it will be <strong>dashelement_cloudflare_snippet1</strong>.</p>
<p><a href="https://xlinesoft.com/blog/wp-content/uploads/2023/12/dahboard_snippet2.png"><img loading="lazy" decoding="async" src="https://xlinesoft.com/blog/wp-content/uploads/2023/12/dahboard_snippet2-600x226.png" alt="" width="600" height="226" class="alignnone size-medium wp-image-3064" srcset="https://xlinesoft.com/blog/wp-content/uploads/2023/12/dahboard_snippet2-600x226.png 600w, https://xlinesoft.com/blog/wp-content/uploads/2023/12/dahboard_snippet2-1024x385.png 1024w, https://xlinesoft.com/blog/wp-content/uploads/2023/12/dahboard_snippet2-768x289.png 768w, https://xlinesoft.com/blog/wp-content/uploads/2023/12/dahboard_snippet2-1536x577.png 1536w, https://xlinesoft.com/blog/wp-content/uploads/2023/12/dahboard_snippet2.png 1623w" sizes="(max-width: 600px) 100vw, 600px" /></a></p>
<p>3. Add the following code to Dashboard: Javascript OnLoad event. Here we are using the ID of the div we just found.  </p>
<div class="my-syntax-highlighter">
<pre><textarea id="mshighlighter" class="mshighlighter" language="javascript" name="mshighlighter" >
$( "#dashelement_cloudflare_snippet1" ).bind( "click", function() {
  location.href = Runner.pages.getUrl("customers","list");
});</textarea></pre>
</div>
<p>This is it. Enjoy!</p>
]]></content:encoded>
					
					<wfw:commentRss>https://xlinesoft.com/blog/2023/12/19/clickable-code-snippet-in-a-dashboard/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
